Add Class.getPrimitiveClass().

Implement the native part in ART and remove the native parts
of the previously needed workaround for java.lang.Void.TYPE.

Companion libcore/ change:
    https://android-review.googlesource.com/619326

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: Pixel 2 XL boots.
Bug: 73346078
Change-Id: Icfb201a1f08d8ff2a65c58f7c0ec25aa2296db29
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 832d50e..4c706c3 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -244,7 +244,6 @@
         "native/java_lang_Thread.cc",
         "native/java_lang_Throwable.cc",
         "native/java_lang_VMClassLoader.cc",
-        "native/java_lang_Void.cc",
         "native/java_lang_invoke_MethodHandleImpl.cc",
         "native/java_lang_ref_FinalizerReference.cc",
         "native/java_lang_ref_Reference.cc",
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 85acc71..f8dd829 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -235,6 +235,20 @@
   UnstartedClassForNameCommon(self, shadow_frame, result, arg_offset, true, "Class.forName");
 }
 
+void UnstartedRuntime::UnstartedClassGetPrimitiveClass(
+    Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
+  ObjPtr<mirror::String> class_name = GetClassName(self, shadow_frame, arg_offset);
+  ObjPtr<mirror::Class> klass = mirror::Class::GetPrimitiveClass(class_name);
+  if (UNLIKELY(klass == nullptr)) {
+    DCHECK(self->IsExceptionPending());
+    AbortTransactionOrFail(self,
+                           "Class.getPrimitiveClass() failed: %s",
+                           self->GetException()->GetDetailMessage()->ToModifiedUtf8().c_str());
+    return;
+  }
+  result->SetL(klass);
+}
+
 void UnstartedRuntime::UnstartedClassClassForName(
     Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
   UnstartedClassForNameCommon(self, shadow_frame, result, arg_offset, true, "Class.classForName");
@@ -738,12 +752,6 @@
   }
 }
 
-void UnstartedRuntime::UnstartedVoidLookupType(
-    Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame ATTRIBUTE_UNUSED, JValue* result,
-    size_t arg_offset ATTRIBUTE_UNUSED) {
-  result->SetL(Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V'));
-}
-
 // Arraycopy emulation.
 // Note: we can't use any fast copy functions, as they are not available under transaction.
 
diff --git a/runtime/interpreter/unstarted_runtime_list.h b/runtime/interpreter/unstarted_runtime_list.h
index c029e07..3cc598a 100644
--- a/runtime/interpreter/unstarted_runtime_list.h
+++ b/runtime/interpreter/unstarted_runtime_list.h
@@ -23,6 +23,7 @@
   V(CharacterToUpperCase, "int java.lang.Character.toUpperCase(int)") \
   V(ClassForName, "java.lang.Class java.lang.Class.forName(java.lang.String)") \
   V(ClassForNameLong, "java.lang.Class java.lang.Class.forName(java.lang.String, boolean, java.lang.ClassLoader)") \
+  V(ClassGetPrimitiveClass, "java.lang.Class java.lang.Class.getPrimitiveClass(java.lang.String)") \
   V(ClassClassForName, "java.lang.Class java.lang.Class.classForName(java.lang.String, boolean, java.lang.ClassLoader)") \
   V(ClassNewInstance, "java.lang.Object java.lang.Class.newInstance()") \
   V(ClassGetDeclaredField, "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)") \
@@ -36,7 +37,6 @@
   V(ClassLoaderGetResourceAsStream, "java.io.InputStream java.lang.ClassLoader.getResourceAsStream(java.lang.String)") \
   V(ConstructorNewInstance0, "java.lang.Object java.lang.reflect.Constructor.newInstance0(java.lang.Object[])") \
   V(VmClassLoaderFindLoadedClass, "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") \
-  V(VoidLookupType, "java.lang.Class java.lang.Void.lookupType()") \
   V(SystemArraycopy, "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)") \
   V(SystemArraycopyByte, "void java.lang.System.arraycopy(byte[], int, byte[], int, int)") \
   V(SystemArraycopyChar, "void java.lang.System.arraycopy(char[], int, char[], int, int)") \
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 9246bae..5d730ce 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -72,6 +72,42 @@
   java_lang_Class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
 }
 
+ObjPtr<mirror::Class> Class::GetPrimitiveClass(ObjPtr<mirror::String> name) {
+  const char* expected_name = nullptr;
+  ClassLinker::ClassRoot class_root = ClassLinker::kJavaLangObject;  // Invalid.
+  if (name != nullptr && name->GetLength() >= 2) {
+    // Perfect hash for the expected values: from the second letters of the primitive types,
+    // only 'y' has the bit 0x10 set, so use it to change 'b' to 'B'.
+    char hash = name->CharAt(0) ^ ((name->CharAt(1) & 0x10) << 1);
+    switch (hash) {
+      case 'b': expected_name = "boolean"; class_root = ClassLinker::kPrimitiveBoolean; break;
+      case 'B': expected_name = "byte";    class_root = ClassLinker::kPrimitiveByte;    break;
+      case 'c': expected_name = "char";    class_root = ClassLinker::kPrimitiveChar;    break;
+      case 'd': expected_name = "double";  class_root = ClassLinker::kPrimitiveDouble;  break;
+      case 'f': expected_name = "float";   class_root = ClassLinker::kPrimitiveFloat;   break;
+      case 'i': expected_name = "int";     class_root = ClassLinker::kPrimitiveInt;     break;
+      case 'l': expected_name = "long";    class_root = ClassLinker::kPrimitiveLong;    break;
+      case 's': expected_name = "short";   class_root = ClassLinker::kPrimitiveShort;   break;
+      case 'v': expected_name = "void";    class_root = ClassLinker::kPrimitiveVoid;    break;
+      default: break;
+    }
+  }
+  if (expected_name != nullptr && name->Equals(expected_name)) {
+    ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->GetClassRoot(class_root);
+    DCHECK(klass != nullptr);
+    return klass;
+  } else {
+    Thread* self = Thread::Current();
+    if (name == nullptr) {
+      // Note: ThrowNullPointerException() requires a message which we deliberately want to omit.
+      self->ThrowNewException("Ljava/lang/NullPointerException;", /* msg */ nullptr);
+    } else {
+      self->ThrowNewException("Ljava/lang/ClassNotFoundException;", name->ToModifiedUtf8().c_str());
+    }
+    return nullptr;
+  }
+}
+
 ClassExt* Class::EnsureExtDataPresent(Thread* self) {
   ObjPtr<ClassExt> existing(GetExtData());
   if (!existing.IsNull()) {
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index b5deffb..b9a31e5 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -1134,6 +1134,10 @@
   void VisitNativeRoots(Visitor& visitor, PointerSize pointer_size)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Get one of the primitive classes.
+  static ObjPtr<mirror::Class> GetPrimitiveClass(ObjPtr<mirror::String> name)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   // When class is verified, set the kAccSkipAccessChecks flag on each method.
   void SetSkipAccessChecksFlagOnAllMethods(PointerSize pointer_size)
       REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 4597f68..e518553 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -176,6 +176,12 @@
   return soa.AddLocalReference<jclass>(c.Get());
 }
 
+static jclass Class_getPrimitiveClass(JNIEnv* env, jclass, jstring name) {
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Class> klass = mirror::Class::GetPrimitiveClass(soa.Decode<mirror::String>(name));
+  return soa.AddLocalReference<jclass>(klass);
+}
+
 static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
@@ -869,6 +875,7 @@
   FAST_NATIVE_METHOD(Class, getInnerClassFlags, "(I)I"),
   FAST_NATIVE_METHOD(Class, getInnerClassName, "()Ljava/lang/String;"),
   FAST_NATIVE_METHOD(Class, getInterfacesInternal, "()[Ljava/lang/Class;"),
+  FAST_NATIVE_METHOD(Class, getPrimitiveClass, "(Ljava/lang/String;)Ljava/lang/Class;"),
   FAST_NATIVE_METHOD(Class, getNameNative, "()Ljava/lang/String;"),
   FAST_NATIVE_METHOD(Class, getPublicDeclaredFields, "()[Ljava/lang/reflect/Field;"),
   FAST_NATIVE_METHOD(Class, getSignatureAnnotation, "()[Ljava/lang/String;"),
diff --git a/runtime/native/java_lang_Void.cc b/runtime/native/java_lang_Void.cc
deleted file mode 100644
index af83dd1..0000000
--- a/runtime/native/java_lang_Void.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "java_lang_Void.h"
-
-#include "nativehelper/jni_macros.h"
-
-#include "class_linker-inl.h"
-#include "jni_internal.h"
-#include "native_util.h"
-#include "runtime.h"
-#include "scoped_fast_native_object_access-inl.h"
-
-namespace art {
-
-static jclass Void_lookupType(JNIEnv* env, jclass) {
-  ScopedFastNativeObjectAccess soa(env);
-  return soa.AddLocalReference<jclass>(
-      Runtime::Current()->GetClassLinker()->GetClassRoot(ClassLinker::kPrimitiveVoid));
-}
-
-static JNINativeMethod gMethods[] = {
-  FAST_NATIVE_METHOD(Void, lookupType, "()Ljava/lang/Class;"),
-};
-
-void register_java_lang_Void(JNIEnv* env) {
-  REGISTER_NATIVE_METHODS("java/lang/Void");
-}
-
-}  // namespace art
diff --git a/runtime/native/java_lang_Void.h b/runtime/native/java_lang_Void.h
deleted file mode 100644
index 8777d80..0000000
--- a/runtime/native/java_lang_Void.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_NATIVE_JAVA_LANG_VOID_H_
-#define ART_RUNTIME_NATIVE_JAVA_LANG_VOID_H_
-
-#include <jni.h>
-
-namespace art {
-
-void register_java_lang_Void(JNIEnv* env);
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_VOID_H_
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 7aca12e..d0aec11 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -120,7 +120,6 @@
 #include "native/java_lang_Thread.h"
 #include "native/java_lang_Throwable.h"
 #include "native/java_lang_VMClassLoader.h"
-#include "native/java_lang_Void.h"
 #include "native/java_lang_invoke_MethodHandleImpl.h"
 #include "native/java_lang_ref_FinalizerReference.h"
 #include "native/java_lang_ref_Reference.h"
@@ -1746,7 +1745,6 @@
   register_java_lang_Thread(env);
   register_java_lang_Throwable(env);
   register_java_lang_VMClassLoader(env);
-  register_java_lang_Void(env);
   register_java_util_concurrent_atomic_AtomicLong(env);
   register_libcore_util_CharsetUtils(env);
   register_org_apache_harmony_dalvik_ddmc_DdmServer(env);