Add Android System#arraycopy fast specializations.

Re-added System#arraycopy specializations that are
really fast for small arrays. They were introduced
originally in b/7103825.

Change-Id: Ie8c995852810ad555fe73743d4d40ec45d8d6bbe
diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc
index ee99e78..0ab6f52 100644
--- a/runtime/native/java_lang_System.cc
+++ b/runtime/native/java_lang_System.cc
@@ -26,127 +26,6 @@
 
 namespace art {
 
-/*
- * We make guarantees about the atomicity of accesses to primitive variables.  These guarantees
- * also apply to elements of arrays. In particular, 8-bit, 16-bit, and 32-bit accesses must not
- * cause "word tearing".  Accesses to 64-bit array elements may be two 32-bit operations.
- * References are never torn regardless of the number of bits used to represent them.
- */
-
-static void ThrowArrayStoreException_NotAnArray(const char* identifier, mirror::Object* array)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  std::string actualType(PrettyTypeOf(array));
-  Thread* self = Thread::Current();
-  ThrowLocation throw_location = self->GetCurrentLocationForThrow();
-  self->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayStoreException;",
-                           "%s of type %s is not an array", identifier, actualType.c_str());
-}
-
-static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject javaDst,
-                             jint dstPos, jint length) {
-  // The API is defined in terms of length, but length is somewhat overloaded so we use count.
-  const jint count = length;
-  ScopedFastNativeObjectAccess soa(env);
-
-  // Null pointer checks.
-  if (UNLIKELY(javaSrc == nullptr)) {
-    ThrowNullPointerException(nullptr, "src == null");
-    return;
-  }
-  if (UNLIKELY(javaDst == nullptr)) {
-    ThrowNullPointerException(nullptr, "dst == null");
-    return;
-  }
-
-  // Make sure source and destination are both arrays.
-  mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc);
-  if (UNLIKELY(!srcObject->IsArrayInstance())) {
-    ThrowArrayStoreException_NotAnArray("source", srcObject);
-    return;
-  }
-  mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst);
-  if (UNLIKELY(!dstObject->IsArrayInstance())) {
-    ThrowArrayStoreException_NotAnArray("destination", dstObject);
-    return;
-  }
-  mirror::Array* srcArray = srcObject->AsArray();
-  mirror::Array* dstArray = dstObject->AsArray();
-
-  // Bounds checking.
-  if (UNLIKELY(srcPos < 0) || UNLIKELY(dstPos < 0) || UNLIKELY(count < 0) ||
-      UNLIKELY(srcPos > srcArray->GetLength() - count) ||
-      UNLIKELY(dstPos > dstArray->GetLength() - count)) {
-    ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
-    soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayIndexOutOfBoundsException;",
-                                   "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d",
-                                   srcArray->GetLength(), srcPos, dstArray->GetLength(), dstPos,
-                                   count);
-    return;
-  }
-
-  mirror::Class* dstComponentType = dstArray->GetClass()->GetComponentType();
-  mirror::Class* srcComponentType = srcArray->GetClass()->GetComponentType();
-  Primitive::Type dstComponentPrimitiveType = dstComponentType->GetPrimitiveType();
-
-  if (LIKELY(srcComponentType == dstComponentType)) {
-    // Trivial assignability.
-    switch (dstComponentPrimitiveType) {
-      case Primitive::kPrimVoid:
-        LOG(FATAL) << "Unreachable, cannot have arrays of type void";
-        return;
-      case Primitive::kPrimBoolean:
-      case Primitive::kPrimByte:
-        DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 1U);
-        dstArray->AsByteSizedArray()->Memmove(dstPos, srcArray->AsByteSizedArray(), srcPos, count);
-        return;
-      case Primitive::kPrimChar:
-      case Primitive::kPrimShort:
-        DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 2U);
-        dstArray->AsShortSizedArray()->Memmove(dstPos, srcArray->AsShortSizedArray(), srcPos, count);
-        return;
-      case Primitive::kPrimInt:
-      case Primitive::kPrimFloat:
-        DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 4U);
-        dstArray->AsIntArray()->Memmove(dstPos, srcArray->AsIntArray(), srcPos, count);
-        return;
-      case Primitive::kPrimLong:
-      case Primitive::kPrimDouble:
-        DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 8U);
-        dstArray->AsLongArray()->Memmove(dstPos, srcArray->AsLongArray(), srcPos, count);
-        return;
-      case Primitive::kPrimNot: {
-        mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>();
-        mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>();
-        dstObjArray->AssignableMemmove(dstPos, srcObjArray, srcPos, count);
-        return;
-      }
-      default:
-        LOG(FATAL) << "Unknown array type: " << PrettyTypeOf(srcArray);
-        return;
-    }
-  }
-  // If one of the arrays holds a primitive type the other array must hold the exact same type.
-  if (UNLIKELY((dstComponentPrimitiveType != Primitive::kPrimNot) ||
-               srcComponentType->IsPrimitive())) {
-    std::string srcType(PrettyTypeOf(srcArray));
-    std::string dstType(PrettyTypeOf(dstArray));
-    ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
-    soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayStoreException;",
-                                   "Incompatible types: src=%s, dst=%s",
-                                   srcType.c_str(), dstType.c_str());
-    return;
-  }
-  // Arrays hold distinct types and so therefore can't alias - use memcpy instead of memmove.
-  mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>();
-  mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>();
-  // If we're assigning into say Object[] then we don't need per element checks.
-  if (dstComponentType->IsAssignableFrom(srcComponentType)) {
-    dstObjArray->AssignableMemcpy(dstPos, srcObjArray, srcPos, count);
-    return;
-  }
-  dstObjArray->AssignableCheckingMemcpy(dstPos, srcObjArray, srcPos, count, true);
-}
-
 // Template to convert general array to that of its specific primitive type.
 template <typename T>
 inline T* AsPrimitiveArray(mirror::Array* array) {
@@ -216,17 +95,7 @@
       javaDst, dstPos, count);
 }
 
-static jint System_identityHashCode(JNIEnv* env, jclass, jobject javaObject) {
-  if (UNLIKELY(javaObject == nullptr)) {
-    return 0;
-  }
-  ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* o = soa.Decode<mirror::Object*>(javaObject);
-  return static_cast<jint>(o->IdentityHashCode());
-}
-
 static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(System, arraycopy, "!(Ljava/lang/Object;ILjava/lang/Object;II)V"),
   NATIVE_METHOD(System, arraycopyCharUnchecked, "!([CI[CII)V"),
   NATIVE_METHOD(System, arraycopyByteUnchecked, "!([BI[BII)V"),
   NATIVE_METHOD(System, arraycopyShortUnchecked, "!([SI[SII)V"),
@@ -235,7 +104,6 @@
   NATIVE_METHOD(System, arraycopyFloatUnchecked, "!([FI[FII)V"),
   NATIVE_METHOD(System, arraycopyDoubleUnchecked, "!([DI[DII)V"),
   NATIVE_METHOD(System, arraycopyBooleanUnchecked, "!([ZI[ZII)V"),
-  NATIVE_METHOD(System, identityHashCode, "!(Ljava/lang/Object;)I"),
 };
 
 void register_java_lang_System(JNIEnv* env) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index f9f50b4..3f27e44 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -997,6 +997,7 @@
   REGISTER(register_java_lang_DexCache);
   REGISTER(register_java_lang_Object);
   REGISTER(register_java_lang_Thread);
+  REGISTER(register_java_lang_System);
   REGISTER(register_java_lang_VMClassLoader);
   REGISTER(register_java_lang_ref_FinalizerReference);
   REGISTER(register_java_lang_ref_Reference);