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);