ART: Refactor unstarted runtime

Refactor and clean up unstarted runtime.

Bug: 19542228
Change-Id: Ib3e4b3517e06e8242d4fed32ca59419fef553a47
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 2a9c0d4..26ab602 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -19,6 +19,7 @@
 #include <cmath>
 
 #include "mirror/array-inl.h"
+#include "unstarted_runtime.h"
 
 namespace art {
 namespace interpreter {
@@ -450,10 +451,6 @@
   UNREACHABLE();
 }
 
-static void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_item,
-                                   ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
 // Assign register 'src_reg' from shadow_frame to register 'dest_reg' into new_shadow_frame.
 static inline void AssignRegister(ShadowFrame* new_shadow_frame, const ShadowFrame& shadow_frame,
                                   size_t dest_reg, size_t src_reg)
@@ -733,279 +730,6 @@
   }
 }
 
-// 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()).c_str());
-    }
-    return;
-  }
-  if (found != nullptr && initialize_class) {
-    StackHandleScope<1> hs(self);
-    Handle<mirror::Class> h_class(hs.NewHandle(found));
-    if (!class_linker->EnsureInitialized(self, h_class, true, true)) {
-      CHECK(self->IsExceptionPending());
-      return;
-    }
-  }
-  result->SetL(found);
-}
-
-// Common helper for class-loading cutouts in an unstarted runtime. We call Runtime methods that
-// rely on Java code to wrap errors in the correct exception class (i.e., NoClassDefFoundError into
-// ClassNotFoundException), so need to do the same. The only exception is if the exception is
-// actually InternalError. This must not be wrapped, as it signals an initialization abort.
-static void CheckExceptionGenerateClassNotFound(Thread* self)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  if (self->IsExceptionPending()) {
-    // If it is not an InternalError, wrap it.
-    std::string type(PrettyTypeOf(self->GetException()));
-    if (type != "java.lang.InternalError") {
-      self->ThrowNewWrappedException("Ljava/lang/ClassNotFoundException;",
-                                     "ClassNotFoundException");
-    }
-  }
-}
-
-static void UnstartedRuntimeInvoke(Thread* self,  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)") {
-    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, false);
-    CheckExceptionGenerateClassNotFound(self);
-  } else if (name == "java.lang.Class java.lang.Class.forName(java.lang.String, boolean, java.lang.ClassLoader)") {
-    mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString();
-    bool initialize_class = shadow_frame->GetVReg(arg_offset + 1) != 0;
-    mirror::ClassLoader* class_loader =
-        down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset + 2));
-    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, initialize_class,
-                              false);
-    CheckExceptionGenerateClassNotFound(self);
-  } else if (name == "java.lang.Class java.lang.Class.classForName(java.lang.String, boolean, java.lang.ClassLoader)") {
-    mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString();
-    bool initialize_class = shadow_frame->GetVReg(arg_offset + 1) != 0;
-    mirror::ClassLoader* class_loader =
-        down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset + 2));
-    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, initialize_class,
-                              false);
-    CheckExceptionGenerateClassNotFound(self);
-  } 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);
-    // This might have an error pending. But semantics are to just return null.
-    if (self->IsExceptionPending()) {
-      // If it is an InternalError, keep it. See CheckExceptionGenerateClassNotFound.
-      std::string type(PrettyTypeOf(self->GetException()));
-      if (type != "java.lang.InternalError") {
-        self->ClearException();
-      }
-    }
-  } else if (name == "java.lang.Class java.lang.Void.lookupType()") {
-    result->SetL(Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V'));
-  } else if (name == "java.lang.Object java.lang.Class.newInstance()") {
-    StackHandleScope<3> hs(self);  // Class, constructor, object.
-    Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
-    Handle<Class> h_klass(hs.NewHandle(klass));
-    // There are two situations in which we'll abort this run.
-    //  1) If the class isn't yet initialized and initialization fails.
-    //  2) If we can't find the default constructor. We'll postpone the exception to runtime.
-    // Note that 2) could likely be handled here, but for safety abort the transaction.
-    bool ok = false;
-    if (Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_klass, true, true)) {
-      Handle<ArtMethod> h_cons(hs.NewHandle(h_klass->FindDeclaredDirectMethod("<init>", "()V")));
-      if (h_cons.Get() != nullptr) {
-        Handle<Object> h_obj(hs.NewHandle(klass->AllocObject(self)));
-        CHECK(h_obj.Get() != nullptr);  // We don't expect OOM at compile-time.
-        EnterInterpreterFromInvoke(self, h_cons.Get(), h_obj.Get(), nullptr, nullptr);
-        if (!self->IsExceptionPending()) {
-          result->SetL(h_obj.Get());
-          ok = true;
-        }
-      } else {
-        self->ThrowNewExceptionF("Ljava/lang/InternalError;",
-                                 "Could not find default constructor for '%s'",
-                                 PrettyClass(h_klass.Get()).c_str());
-      }
-    }
-    if (!ok) {
-      std::string error_msg = StringPrintf("Failed in Class.newInstance for '%s' with %s",
-                                           PrettyClass(h_klass.Get()).c_str(),
-                                           PrettyTypeOf(self->GetException()).c_str());
-      self->ThrowNewWrappedException("Ljava/lang/InternalError;", error_msg.c_str());
-    }
-  } else if (name == "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)") {
-    // Special managed code cut-out to allow field lookup in a un-started runtime that'd fail
-    // going the reflective Dex way.
-    Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
-    String* name2 = shadow_frame->GetVRegReference(arg_offset + 1)->AsString();
-    ArtField* found = NULL;
-    ObjectArray<ArtField>* fields = klass->GetIFields();
-    for (int32_t i = 0; i < fields->GetLength() && found == NULL; ++i) {
-      ArtField* f = fields->Get(i);
-      if (name2->Equals(f->GetName())) {
-        found = f;
-      }
-    }
-    if (found == NULL) {
-      fields = klass->GetSFields();
-      for (int32_t i = 0; i < fields->GetLength() && found == NULL; ++i) {
-        ArtField* f = fields->Get(i);
-        if (name2->Equals(f->GetName())) {
-          found = f;
-        }
-      }
-    }
-    CHECK(found != NULL)
-        << "Failed to find field in Class.getDeclaredField in un-started runtime. name="
-        << name2->ToModifiedUtf8() << " class=" << PrettyDescriptor(klass);
-    // TODO: getDeclaredField calls GetType once the field is found to ensure a
-    //       NoClassDefFoundError is thrown if the field's type cannot be resolved.
-    Class* jlr_Field = self->DecodeJObject(WellKnownClasses::java_lang_reflect_Field)->AsClass();
-    StackHandleScope<1> hs(self);
-    Handle<Object> field(hs.NewHandle(jlr_Field->AllocNonMovableObject(self)));
-    CHECK(field.Get() != NULL);
-    ArtMethod* c = jlr_Field->FindDeclaredDirectMethod("<init>", "(Ljava/lang/reflect/ArtField;)V");
-    uint32_t args[1];
-    args[0] = StackReference<mirror::Object>::FromMirrorPtr(found).AsVRegValue();
-    EnterInterpreterFromInvoke(self, c, field.Get(), args, NULL);
-    result->SetL(field.Get());
-  } else if (name == "int java.lang.Object.hashCode()") {
-    Object* obj = shadow_frame->GetVRegReference(arg_offset);
-    result->SetI(obj->IdentityHashCode());
-  } else if (name == "java.lang.String java.lang.reflect.ArtMethod.getMethodName(java.lang.reflect.ArtMethod)") {
-    mirror::ArtMethod* method = shadow_frame->GetVRegReference(arg_offset)->AsArtMethod();
-    result->SetL(method->GetNameAsString(self));
-  } else if (name == "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)" ||
-             name == "void java.lang.System.arraycopy(char[], int, char[], int, int)" ||
-             name == "void java.lang.System.arraycopy(int[], int, int[], int, int)") {
-    // Special case array copying without initializing System.
-    Class* ctype = shadow_frame->GetVRegReference(arg_offset)->GetClass()->GetComponentType();
-    jint srcPos = shadow_frame->GetVReg(arg_offset + 1);
-    jint dstPos = shadow_frame->GetVReg(arg_offset + 3);
-    jint length = shadow_frame->GetVReg(arg_offset + 4);
-    if (!ctype->IsPrimitive()) {
-      ObjectArray<Object>* src = shadow_frame->GetVRegReference(arg_offset)->AsObjectArray<Object>();
-      ObjectArray<Object>* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsObjectArray<Object>();
-      for (jint i = 0; i < length; ++i) {
-        dst->Set(dstPos + i, src->Get(srcPos + i));
-      }
-    } else if (ctype->IsPrimitiveChar()) {
-      CharArray* src = shadow_frame->GetVRegReference(arg_offset)->AsCharArray();
-      CharArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsCharArray();
-      for (jint i = 0; i < length; ++i) {
-        dst->Set(dstPos + i, src->Get(srcPos + i));
-      }
-    } else if (ctype->IsPrimitiveInt()) {
-      IntArray* src = shadow_frame->GetVRegReference(arg_offset)->AsIntArray();
-      IntArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsIntArray();
-      for (jint i = 0; i < length; ++i) {
-        dst->Set(dstPos + i, src->Get(srcPos + i));
-      }
-    } else {
-      self->ThrowNewExceptionF("Ljava/lang/InternalError;",
-                               "Unimplemented System.arraycopy for type '%s'",
-                               PrettyDescriptor(ctype).c_str());
-    }
-  } else if (name == "long java.lang.Double.doubleToRawLongBits(double)") {
-    double in = shadow_frame->GetVRegDouble(arg_offset);
-    result->SetJ(bit_cast<int64_t>(in));
-  } else if (name == "double java.lang.Math.ceil(double)") {
-    double in = shadow_frame->GetVRegDouble(arg_offset);
-    double out;
-    // Special cases:
-    // 1) NaN, infinity, +0, -0 -> out := in. All are guaranteed by cmath.
-    // -1 < in < 0 -> out := -0.
-    if (-1.0 < in && in < 0) {
-      out = -0.0;
-    } else {
-      out = ceil(in);
-    }
-    result->SetD(out);
-  } else if (name == "java.lang.Object java.lang.ThreadLocal.get()") {
-    std::string caller(PrettyMethod(shadow_frame->GetLink()->GetMethod()));
-    bool ok = false;
-    if (caller == "java.lang.String java.lang.IntegralToString.convertInt(java.lang.AbstractStringBuilder, int)") {
-      // Allocate non-threadlocal buffer.
-      result->SetL(mirror::CharArray::Alloc(self, 11));
-      ok = true;
-    } else if (caller == "java.lang.RealToString java.lang.RealToString.getInstance()") {
-      // Note: RealToString is implemented and used in a different fashion than IntegralToString.
-      // Conversion is done over an actual object of RealToString (the conversion method is an
-      // instance method). This means it is not as clear whether it is correct to return a new
-      // object each time. The caller needs to be inspected by hand to see whether it (incorrectly)
-      // stores the object for later use.
-      // See also b/19548084 for a possible rewrite and bringing it in line with IntegralToString.
-      if (shadow_frame->GetLink()->GetLink() != nullptr) {
-        std::string caller2(PrettyMethod(shadow_frame->GetLink()->GetLink()->GetMethod()));
-        if (caller2 == "java.lang.String java.lang.Double.toString(double)") {
-          // Allocate new object.
-          StackHandleScope<2> hs(self);
-          Handle<Class> h_real_to_string_class(hs.NewHandle(
-              shadow_frame->GetLink()->GetMethod()->GetDeclaringClass()));
-          Handle<Object> h_real_to_string_obj(hs.NewHandle(
-              h_real_to_string_class->AllocObject(self)));
-          if (h_real_to_string_obj.Get() != nullptr) {
-            mirror::ArtMethod* init_method =
-                h_real_to_string_class->FindDirectMethod("<init>", "()V");
-            if (init_method == nullptr) {
-              h_real_to_string_class->DumpClass(LOG(FATAL), mirror::Class::kDumpClassFullDetail);
-            } else {
-              JValue invoke_result;
-              EnterInterpreterFromInvoke(self, init_method, h_real_to_string_obj.Get(), nullptr,
-                                         nullptr);
-              if (!self->IsExceptionPending()) {
-                result->SetL(h_real_to_string_obj.Get());
-                ok = true;
-              }
-            }
-          }
-
-          if (!ok) {
-            // We'll abort, so clear exception.
-            self->ClearException();
-          }
-        }
-      }
-    }
-
-    if (!ok) {
-      self->ThrowNewException("Ljava/lang/InternalError;", "Unimplemented ThreadLocal.get");
-    }
-  } else {
-    // Not special, continue with regular interpreter execution.
-    artInterpreterToInterpreterBridge(self, code_item, shadow_frame, result);
-  }
-}
-
 // Explicit DoCall template function declarations.
 #define EXPLICIT_DO_CALL_TEMPLATE_DECL(_is_range, _do_assignability_check)                      \
   template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                          \