Fix java.lang.Void.TYPE (void.class) initialization.
Do not rely on the DexCache resolved types now that entries
can be evicted.
Test: 157-void-class
Test: testrunner.py --host
Bug: 35652776
Bug: 30627598
Change-Id: Ic384174ae1849072568dd6d2ff9cc60d7f7f1880
diff --git a/runtime/Android.bp b/runtime/Android.bp
index b4c7b9c..9958814 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -156,6 +156,7 @@
"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/class_linker.cc b/runtime/class_linker.cc
index 9b0ffaf..9fefed6 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -752,22 +752,6 @@
FindSystemClass(self, "[Ljava/lang/StackTraceElement;"));
mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
- // Ensure void type is resolved in the core's dex cache so java.lang.Void is correctly
- // initialized.
- {
- const DexFile& dex_file = java_lang_Object->GetDexFile();
- const DexFile::TypeId* void_type_id = dex_file.FindTypeId("V");
- CHECK(void_type_id != nullptr);
- dex::TypeIndex void_type_idx = dex_file.GetIndexForTypeId(*void_type_id);
- // Now we resolve void type so the dex cache contains it. We use java.lang.Object class
- // as referrer so the used dex cache is core's one.
- ObjPtr<mirror::Class> resolved_type = ResolveType(dex_file,
- void_type_idx,
- java_lang_Object.Get());
- CHECK_EQ(resolved_type, GetClassRoot(kPrimitiveVoid));
- self->AssertNoPendingException();
- }
-
// Create conflict tables that depend on the class linker.
runtime->FixupConflictTables();
@@ -4162,19 +4146,6 @@
return false;
}
- // We may be running with a preopted oat file but without image. In this case,
- // we don't skip verification of skip_access_checks classes to ensure we initialize
- // dex caches with all types resolved during verification.
- // We need to trust image classes, as these might be coming out of a pre-opted, quickened boot
- // image (that we just failed loading), and the verifier can't be run on quickened opcodes when
- // the runtime isn't started. On the other hand, app classes can be re-verified even if they are
- // already pre-opted, as then the runtime is started.
- if (!Runtime::Current()->IsAotCompiler() &&
- !Runtime::Current()->GetHeap()->HasBootImageSpace() &&
- klass->GetClassLoader() != nullptr) {
- return false;
- }
-
uint16_t class_def_index = klass->GetDexClassDefIndex();
oat_file_class_status = oat_dex_file->GetOatClass(class_def_index).GetStatus();
if (oat_file_class_status == mirror::Class::kStatusVerified ||
diff --git a/runtime/native/java_lang_Void.cc b/runtime/native/java_lang_Void.cc
new file mode 100644
index 0000000..96bfd1b
--- /dev/null
+++ b/runtime/native/java_lang_Void.cc
@@ -0,0 +1,40 @@
+/*
+ * 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 "class_linker.h"
+#include "jni_internal.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
new file mode 100644
index 0000000..8777d80
--- /dev/null
+++ b/runtime/native/java_lang_Void.h
@@ -0,0 +1,28 @@
+/*
+ * 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 69dcfeb..42a0ca9 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -114,6 +114,7 @@
#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"
@@ -1556,6 +1557,7 @@
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);
diff --git a/test/157-void-class/expected.txt b/test/157-void-class/expected.txt
new file mode 100644
index 0000000..3f61c0b
--- /dev/null
+++ b/test/157-void-class/expected.txt
@@ -0,0 +1,2 @@
+JNI_OnLoad called
+void.class = void
diff --git a/test/157-void-class/info.txt b/test/157-void-class/info.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/157-void-class/info.txt
diff --git a/test/157-void-class/run b/test/157-void-class/run
new file mode 100755
index 0000000..59e852c
--- /dev/null
+++ b/test/157-void-class/run
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# 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.
+
+# Let the test build its own core image with --no-image and use verify-profile,
+# so that the compiler does not try to initialize classes. This leaves the
+# java.lang.Void compile-time verified but uninitialized.
+./default-run "$@" --no-image \
+ --runtime-option -Ximage-compiler-option \
+ --runtime-option --compiler-filter=verify-profile
diff --git a/test/157-void-class/src/Main.java b/test/157-void-class/src/Main.java
new file mode 100644
index 0000000..322b705
--- /dev/null
+++ b/test/157-void-class/src/Main.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+import libcore.util.EmptyArray;
+
+public class Main {
+ public static void main(String[] args) {
+ try {
+ // Check if we're running dalvik or RI.
+ Class<?> class_loader_class = Class.forName("dalvik.system.PathClassLoader");
+ System.loadLibrary(args[0]);
+ } catch (ClassNotFoundException e) {
+ usingRI = true;
+ // Add expected JNI_OnLoad log line to match expected.txt.
+ System.out.println("JNI_OnLoad called");
+ }
+ try {
+ // Initialize all classes needed for old java.lang.Void.TYPE initialization.
+ Runnable.class.getMethod("run", EmptyArray.CLASS).getReturnType();
+ } catch (Exception e) {
+ throw new Error(e);
+ }
+ // Clear the resolved types of the ojluni dex file to make sure there is no entry
+ // for "V", i.e. void.
+ clearResolvedTypes(Integer.class);
+ // With java.lang.Void being compile-time verified but uninitialized, initialize
+ // it now. Previously, this would indirectly initialize TYPE with the current,
+ // i.e. zero-initialized, value of TYPE. The only thing that could prevent the
+ // series of calls leading to this was a cache hit in Class.getDexCacheType()
+ // which we have prevented by clearing the cache above.
+ Class<?> voidClass = void.class;
+ System.out.println("void.class = " + voidClass);
+ }
+
+ public static void clearResolvedTypes(Class<?> c) {
+ if (!usingRI) {
+ nativeClearResolvedTypes(c);
+ }
+ }
+
+ public static native void nativeClearResolvedTypes(Class<?> c);
+
+ static boolean usingRI = false;
+}
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index f3d4332..99926aa 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -371,6 +371,22 @@
if [ "$HAVE_IMAGE" = "n" ]; then
+ if [ "${HOST}" = "y" ]; then
+ framework="${ANDROID_HOST_OUT}/framework"
+ bpath_suffix="-hostdex"
+ else
+ framework="${ANDROID_ROOT}/framework"
+ bpath_suffix=""
+ fi
+ # TODO If the target was compiled WITH_DEXPREOPT=true then these tests will
+ # fail since these jar files will be stripped.
+ bpath="${framework}/core-libart${bpath_suffix}.jar"
+ bpath="${bpath}:${framework}/core-oj${bpath_suffix}.jar"
+ bpath="${bpath}:${framework}/conscrypt${bpath_suffix}.jar"
+ bpath="${bpath}:${framework}/okhttp${bpath_suffix}.jar"
+ bpath="${bpath}:${framework}/bouncycastle${bpath_suffix}.jar"
+ # Pass down the bootclasspath
+ FLAGS="${FLAGS} -Xbootclasspath:${bpath}"
# Add 5 minutes to give some time to generate the boot image.
TIME_OUT_VALUE=$((${TIME_OUT_VALUE} + 300))
DALVIKVM_BOOT_OPT="-Ximage:/system/non-existant/core.art"
diff --git a/test/run-test b/test/run-test
index e808dee..92d7d88 100755
--- a/test/run-test
+++ b/test/run-test
@@ -525,22 +525,6 @@
err_echo "--no-image is only supported on the art runtime"
exit 1
fi
- if [ "$target_mode" = "no" ]; then
- framework="${ANDROID_HOST_OUT}/framework"
- bpath_suffix="-hostdex"
- else
- framework="${android_root}/framework"
- bpath_suffix=""
- fi
- # TODO If the target was compiled WITH_DEXPREOPT=true then these tests will
- # fail since these jar files will be stripped.
- bpath="${framework}/core-libart${bpath_suffix}.jar"
- bpath="${bpath}:${framework}/core-oj${bpath_suffix}.jar"
- bpath="${bpath}:${framework}/conscrypt${bpath_suffix}.jar"
- bpath="${bpath}:${framework}/okhttp${bpath_suffix}.jar"
- bpath="${bpath}:${framework}/bouncycastle${bpath_suffix}.jar"
- # Pass down the bootclasspath
- run_args="${run_args} --runtime-option -Xbootclasspath:${bpath}"
run_args="${run_args} --no-image"
fi