diff options
| author | 2017-02-24 14:58:29 +0000 | |
|---|---|---|
| committer | 2017-02-27 16:31:42 +0000 | |
| commit | e00e5590a9cfb72c89294dd7a5480e5fa69a90b9 (patch) | |
| tree | 7eb9254bd6cfe10b2c4005e9cdec3a7cfbb2f442 | |
| parent | 06f658ab309a5f1930b8a6bc306ef79d0ef0616e (diff) | |
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
| -rw-r--r-- | runtime/Android.bp | 1 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 29 | ||||
| -rw-r--r-- | runtime/native/java_lang_Void.cc | 40 | ||||
| -rw-r--r-- | runtime/native/java_lang_Void.h | 28 | ||||
| -rw-r--r-- | runtime/runtime.cc | 2 | ||||
| -rw-r--r-- | test/157-void-class/expected.txt | 2 | ||||
| -rw-r--r-- | test/157-void-class/info.txt | 0 | ||||
| -rwxr-xr-x | test/157-void-class/run | 22 | ||||
| -rw-r--r-- | test/157-void-class/src/Main.java | 57 | ||||
| -rwxr-xr-x | test/etc/run-test-jar | 16 | ||||
| -rwxr-xr-x | test/run-test | 16 |
11 files changed, 168 insertions, 45 deletions
diff --git a/runtime/Android.bp b/runtime/Android.bp index b4c7b9cc6a..9958814f58 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -156,6 +156,7 @@ cc_defaults { "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 9b0ffaf031..9fefed64db 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -752,22 +752,6 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b 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 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, 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 0000000000..96bfd1b4fb --- /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 0000000000..8777d8068c --- /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 69dcfebcb1..42a0ca9373 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 @@ void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) { 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 0000000000..3f61c0b5b0 --- /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 0000000000..e69de29bb2 --- /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 0000000000..59e852c8cd --- /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 0000000000..322b705f1d --- /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 f3d4332009..99926aa9a3 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -371,6 +371,22 @@ fi 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 e808deef52..92d7d88abc 100755 --- a/test/run-test +++ b/test/run-test @@ -525,22 +525,6 @@ if [ "$have_image" = "no" ]; then 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 |