Add runtime_support_common.

Addressed the issue that we shouldn't maintain 2 copies of almost the
same code.

Change-Id: I212656f65e6c47e1167a193c1024100ae97f0028
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 9bf2086..7e4e410 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -23,6 +23,7 @@
 #include "object.h"
 #include "object_utils.h"
 #include "reflection.h"
+#include "runtime_support_common.h"
 #include "trace.h"
 #include "ScopedLocalRef.h"
 
@@ -79,81 +80,6 @@
   self->SetTopOfStack(sp, 0);
 }
 
-static void ThrowNewIllegalAccessErrorClass(Thread* self, Class* referrer, Class* accessed) {
-  self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
-                           "illegal class access: '%s' -> '%s'",
-                           PrettyDescriptor(referrer).c_str(),
-                           PrettyDescriptor(accessed).c_str());
-}
-
-static void ThrowNewIllegalAccessErrorClassForMethodDispatch(Thread* self, Class* referrer,
-                                                             Class* accessed, const Method* caller,
-                                                             const Method* called,
-                                                             InvokeType type) {
-  std::ostringstream type_stream;
-  type_stream << type;
-  self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
-                           "illegal class access ('%s' -> '%s')"
-                           "in attempt to invoke %s method '%s' from '%s'",
-                           PrettyDescriptor(referrer).c_str(),
-                           PrettyDescriptor(accessed).c_str(),
-                           type_stream.str().c_str(),
-                           PrettyMethod(called).c_str(),
-                           PrettyMethod(caller).c_str());
-}
-
-static void ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(Thread* self,
-                                                                          const Method* referrer,
-                                                                          const Method* interface_method,
-                                                                          Object* this_object) {
-  Thread::Current()->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
-      "class '%s' does not implement interface '%s' in call to '%s' from '%s'",
-      PrettyDescriptor(this_object->GetClass()).c_str(),
-      PrettyDescriptor(interface_method->GetDeclaringClass()).c_str(),
-      PrettyMethod(interface_method).c_str(), PrettyMethod(referrer).c_str());
-}
-
-static void ThrowNewIllegalAccessErrorField(Thread* self, Class* referrer, Field* accessed) {
-  self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
-                           "Field '%s' is inaccessible to class '%s'",
-                           PrettyField(accessed, false).c_str(),
-                           PrettyDescriptor(referrer).c_str());
-}
-
-static void ThrowNewIllegalAccessErrorFinalField(Thread* self, const Method* referrer, Field* accessed) {
-  self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
-                           "Final field '%s' cannot be written to by method '%s'",
-                           PrettyField(accessed, false).c_str(),
-                           PrettyMethod(referrer).c_str());
-}
-
-static void ThrowNewIllegalAccessErrorMethod(Thread* self, Class* referrer, Method* accessed) {
-  self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
-                           "Method '%s' is inaccessible to class '%s'",
-                           PrettyMethod(accessed).c_str(),
-                           PrettyDescriptor(referrer).c_str());
-}
-
-static void ThrowNullPointerExceptionForFieldAccess(Thread* self, Field* field, bool is_read) {
-  self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
-                           "Attempt to %s field '%s' on a null object reference",
-                           is_read ? "read from" : "write to",
-                           PrettyField(field, true).c_str());
-}
-
-static void ThrowNullPointerExceptionForMethodAccess(Thread* self, Method* caller,
-                                                     uint32_t method_idx, InvokeType type) {
-  const DexFile& dex_file =
-      Runtime::Current()->GetClassLinker()->FindDexFile(caller->GetDeclaringClass()->GetDexCache());
-  std::ostringstream type_stream;
-  type_stream << type;
-  self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
-                           "Attempt to invoke %s method '%s' from '%s' on a null object reference",
-                           type_stream.str().c_str(),
-                           PrettyMethod(method_idx, dex_file, true).c_str(),
-                           PrettyMethod(caller).c_str());
-}
-
 /*
  * Report location to debugger.  Note: dex_pc is the current offset within
  * the method.  However, because the offset alone cannot distinguish between
@@ -655,85 +581,6 @@
 }
 
 
-// Fast path field resolution that can't throw exceptions
-static Field* FindFieldFast(uint32_t field_idx, const Method* referrer, bool is_primitive,
-                            size_t expected_size, bool is_set) {
-  Field* resolved_field = referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
-  if (UNLIKELY(resolved_field == NULL)) {
-    return NULL;
-  }
-  Class* fields_class = resolved_field->GetDeclaringClass();
-  // Check class is initiliazed or initializing
-  if (UNLIKELY(!fields_class->IsInitializing())) {
-    return NULL;
-  }
-  Class* referring_class = referrer->GetDeclaringClass();
-  if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
-               !referring_class->CanAccessMember(fields_class,
-                                                 resolved_field->GetAccessFlags()) ||
-               (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) {
-    // illegal access
-    return NULL;
-  }
-  FieldHelper fh(resolved_field);
-  if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
-               fh.FieldSize() != expected_size)) {
-    return NULL;
-  }
-  return resolved_field;
-}
-
-
-// Slow path field resolution and declaring class initialization
-Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
-                         bool is_static, bool is_primitive, bool is_set, size_t expected_size) {
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
-  if (UNLIKELY(resolved_field == NULL)) {
-    DCHECK(self->IsExceptionPending());  // Throw exception and unwind
-    return NULL;  // failure
-  } else {
-    Class* fields_class = resolved_field->GetDeclaringClass();
-    Class* referring_class = referrer->GetDeclaringClass();
-    if (UNLIKELY(!referring_class->CanAccess(fields_class))) {
-      ThrowNewIllegalAccessErrorClass(self, referring_class, fields_class);
-      return NULL;  // failure
-    } else if (UNLIKELY(!referring_class->CanAccessMember(fields_class,
-                                                          resolved_field->GetAccessFlags()))) {
-      ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field);
-      return NULL;  // failure
-    } else if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
-      ThrowNewIllegalAccessErrorFinalField(self, referrer, resolved_field);
-      return NULL;  // failure
-    } else {
-      FieldHelper fh(resolved_field);
-      if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
-                   fh.FieldSize() != expected_size)) {
-        self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
-                                 "Attempted read of %zd-bit %s on field '%s'",
-                                 expected_size * (32 / sizeof(int32_t)),
-                                 is_primitive ? "primitive" : "non-primitive",
-                                 PrettyField(resolved_field, true).c_str());
-        return NULL;  // failure
-      } else if (!is_static) {
-        // instance fields must be being accessed on an initialized class
-        return resolved_field;
-      } else {
-        // If the class is already initializing, we must be inside <clinit>, or
-        // we'd still be waiting for the lock.
-        if (fields_class->IsInitializing()) {
-          return resolved_field;
-        } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true)) {
-          return resolved_field;
-        } else {
-          DCHECK(self->IsExceptionPending());  // Throw exception and unwind
-          return NULL;  // failure
-        }
-      }
-    }
-  }
-}
-
 extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const Method* referrer,
                                            Thread* self, Method** sp) {
   Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int32_t));
@@ -943,40 +790,6 @@
   return -1;  // failure
 }
 
-// Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
-// cannot be resolved, throw an error. If it can, use it to create an instance.
-// When verification/compiler hasn't been able to verify access, optionally perform an access
-// check.
-static Object* AllocObjectFromCode(uint32_t type_idx, Method* method, Thread* self,
-                                   bool access_check) {
-  Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
-  Runtime* runtime = Runtime::Current();
-  if (UNLIKELY(klass == NULL)) {
-    klass = runtime->GetClassLinker()->ResolveType(type_idx, method);
-    if (klass == NULL) {
-      DCHECK(self->IsExceptionPending());
-      return NULL;  // Failure
-    }
-  }
-  if (access_check) {
-    if (UNLIKELY(!klass->IsInstantiable())) {
-      self->ThrowNewException("Ljava/lang/InstantiationError;",
-                              PrettyDescriptor(klass).c_str());
-      return NULL;  // Failure
-    }
-    Class* referrer = method->GetDeclaringClass();
-    if (UNLIKELY(!referrer->CanAccess(klass))) {
-      ThrowNewIllegalAccessErrorClass(self, referrer, klass);
-      return NULL;  // Failure
-    }
-  }
-  if (!runtime->GetClassLinker()->EnsureInitialized(klass, true)) {
-    DCHECK(self->IsExceptionPending());
-    return NULL;  // Failure
-  }
-  return klass->AllocObject();
-}
-
 extern "C" Object* artAllocObjectFromCode(uint32_t type_idx, Method* method,
                                           Thread* self, Method** sp) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
@@ -989,36 +802,6 @@
   return AllocObjectFromCode(type_idx, method, self, true);
 }
 
-// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
-// it cannot be resolved, throw an error. If it can, use it to create an array.
-// When verification/compiler hasn't been able to verify access, optionally perform an access
-// check.
-static Array* AllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
-                                  Thread* self, bool access_check) {
-  if (UNLIKELY(component_count < 0)) {
-    Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
-                                         component_count);
-    return NULL;  // Failure
-  }
-  Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
-  if (UNLIKELY(klass == NULL)) {  // Not in dex cache so try to resolve
-    klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
-    if (klass == NULL) {  // Error
-      DCHECK(Thread::Current()->IsExceptionPending());
-      return NULL;  // Failure
-    }
-    CHECK(klass->IsArrayClass()) << PrettyClass(klass);
-  }
-  if (access_check) {
-    Class* referrer = method->GetDeclaringClass();
-    if (UNLIKELY(!referrer->CanAccess(klass))) {
-      ThrowNewIllegalAccessErrorClass(self, referrer, klass);
-      return NULL;  // Failure
-    }
-  }
-  return Array::Alloc(klass, component_count);
-}
-
 extern "C" Array* artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
                                         Thread* self, Method** sp) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
@@ -1032,45 +815,6 @@
   return AllocArrayFromCode(type_idx, method, component_count, self, true);
 }
 
-// Helper function to allocate array for FILLED_NEW_ARRAY.
-Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
-                                  Thread* self, bool access_check) {
-  if (UNLIKELY(component_count < 0)) {
-    self->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", component_count);
-    return NULL;  // Failure
-  }
-  Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
-  if (UNLIKELY(klass == NULL)) {  // Not in dex cache so try to resolve
-    klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
-    if (klass == NULL) {  // Error
-      DCHECK(Thread::Current()->IsExceptionPending());
-      return NULL;  // Failure
-    }
-  }
-  if (UNLIKELY(klass->IsPrimitive() && !klass->IsPrimitiveInt())) {
-    if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
-      Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
-          "Bad filled array request for type %s",
-          PrettyDescriptor(klass).c_str());
-    } else {
-      Thread::Current()->ThrowNewExceptionF("Ljava/lang/InternalError;",
-          "Found type %s; filled-new-array not implemented for anything but \'int\'",
-          PrettyDescriptor(klass).c_str());
-    }
-    return NULL;  // Failure
-  } else {
-    if (access_check) {
-      Class* referrer = method->GetDeclaringClass();
-      if (UNLIKELY(!referrer->CanAccess(klass))) {
-        ThrowNewIllegalAccessErrorClass(self, referrer, klass);
-        return NULL;  // Failure
-      }
-    }
-    DCHECK(klass->IsArrayClass()) << PrettyClass(klass);
-    return Array::Alloc(klass, component_count);
-  }
-}
-
 extern "C" Array* artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method,
                                                int32_t component_count, Thread* self, Method** sp) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
@@ -1257,142 +1001,6 @@
   return 0;  // Success
 }
 
-// Fast path method resolution that can't throw exceptions
-static Method* FindMethodFast(uint32_t method_idx, Object* this_object, const Method* referrer,
-                              bool access_check, InvokeType type) {
-  bool is_direct = type == kStatic || type == kDirect;
-  if (UNLIKELY(this_object == NULL && !is_direct)) {
-    return NULL;
-  }
-  Method* resolved_method =
-      referrer->GetDeclaringClass()->GetDexCache()->GetResolvedMethod(method_idx);
-  if (UNLIKELY(resolved_method == NULL)) {
-    return NULL;
-  }
-  if (access_check) {
-    Class* methods_class = resolved_method->GetDeclaringClass();
-    Class* referring_class = referrer->GetDeclaringClass();
-    if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
-                 !referring_class->CanAccessMember(methods_class,
-                                                   resolved_method->GetAccessFlags()))) {
-      // potential illegal access
-      return NULL;
-    }
-  }
-  if (type == kInterface) {  // Most common form of slow path dispatch.
-    return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
-  } else if (is_direct) {
-    return resolved_method;
-  } else if (type == kSuper) {
-    return referrer->GetDeclaringClass()->GetSuperClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
-  } else {
-    DCHECK(type == kVirtual);
-    return this_object->GetClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
-  }
-}
-
-// Slow path method resolution
-static Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
-                                  Thread* self, bool access_check, InvokeType type) {
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  bool is_direct = type == kStatic || type == kDirect;
-  Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, is_direct);
-  if (UNLIKELY(resolved_method == NULL)) {
-    DCHECK(self->IsExceptionPending());  // Throw exception and unwind
-    return NULL;  // failure
-  } else {
-    if (!access_check) {
-      if (is_direct) {
-        return resolved_method;
-      } else if (type == kInterface) {
-        Method* interface_method =
-            this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
-        if (UNLIKELY(interface_method == NULL)) {
-          ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
-                                                                        resolved_method,
-                                                                        this_object);
-          return NULL;  // failure
-        } else {
-          return interface_method;
-        }
-      } else {
-        ObjectArray<Method>* vtable;
-        uint16_t vtable_index = resolved_method->GetMethodIndex();
-        if (type == kSuper) {
-          vtable = referrer->GetDeclaringClass()->GetSuperClass()->GetVTable();
-        } else {
-          vtable = this_object->GetClass()->GetVTable();
-        }
-        // TODO: eliminate bounds check?
-        return vtable->Get(vtable_index);
-      }
-    } else {
-      Class* methods_class = resolved_method->GetDeclaringClass();
-      Class* referring_class = referrer->GetDeclaringClass();
-      if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
-                   !referring_class->CanAccessMember(methods_class,
-                                                     resolved_method->GetAccessFlags()))) {
-        // The referring class can't access the resolved method, this may occur as a result of a
-        // protected method being made public by implementing an interface that re-declares the
-        // method public. Resort to the dex file to determine the correct class for the access check
-        const DexFile& dex_file = class_linker->FindDexFile(referring_class->GetDexCache());
-        methods_class = class_linker->ResolveType(dex_file,
-                                                  dex_file.GetMethodId(method_idx).class_idx_,
-                                                  referring_class);
-        if (UNLIKELY(!referring_class->CanAccess(methods_class))) {
-          ThrowNewIllegalAccessErrorClassForMethodDispatch(self, referring_class, methods_class,
-                                                           referrer, resolved_method, type);
-          return NULL;  // failure
-        } else if (UNLIKELY(!referring_class->CanAccessMember(methods_class,
-                                                              resolved_method->GetAccessFlags()))) {
-          ThrowNewIllegalAccessErrorMethod(self, referring_class, resolved_method);
-          return NULL;  // failure
-        }
-      }
-      if (is_direct) {
-        return resolved_method;
-      } else if (type == kInterface) {
-        Method* interface_method =
-            this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
-        if (UNLIKELY(interface_method == NULL)) {
-          ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
-                                                                        resolved_method,
-                                                                        this_object);
-          return NULL;  // failure
-        } else {
-          return interface_method;
-        }
-      } else {
-        ObjectArray<Method>* vtable;
-        uint16_t vtable_index = resolved_method->GetMethodIndex();
-        if (type == kSuper) {
-          Class* super_class = referring_class->GetSuperClass();
-          if (LIKELY(super_class != NULL)) {
-            vtable = referring_class->GetSuperClass()->GetVTable();
-          } else {
-            vtable = NULL;
-          }
-        } else {
-          vtable = this_object->GetClass()->GetVTable();
-        }
-        if (LIKELY(vtable != NULL &&
-                   vtable_index < static_cast<uint32_t>(vtable->GetLength()))) {
-          return vtable->GetWithoutChecks(vtable_index);
-        } else {
-          // Behavior to agree with that of the verifier
-          self->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;",
-                                   "attempt to invoke %s method '%s' from '%s'"
-                                   " using incorrect form of method dispatch",
-                                   (type == kSuper ? "super class" : "virtual"),
-                                   PrettyMethod(resolved_method).c_str(),
-                                   PrettyMethod(referrer).c_str());
-          return NULL;  // failure
-        }
-      }
-    }
-  }
-}
-
 static uint64_t artInvokeCommon(uint32_t method_idx, Object* this_object, Method* caller_method,
                                 Thread* self, Method** sp, bool access_check, InvokeType type){
   Method* method = FindMethodFast(method_idx, this_object, caller_method, access_check, type);