diff options
| -rw-r--r-- | runtime/verifier/method_verifier.cc | 12 | ||||
| -rw-r--r-- | test/706-jit-skip-compilation/expected.txt | 1 | ||||
| -rw-r--r-- | test/706-jit-skip-compilation/info.txt | 4 | ||||
| -rw-r--r-- | test/706-jit-skip-compilation/run | 19 | ||||
| -rw-r--r-- | test/706-jit-skip-compilation/smali/errclass.smali | 34 | ||||
| -rw-r--r-- | test/706-jit-skip-compilation/src/Main.java | 57 | ||||
| -rw-r--r-- | test/common/runtime_state.cc | 24 | ||||
| -rwxr-xr-x | test/etc/run-test-jar | 11 |
8 files changed, 160 insertions, 2 deletions
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 7e23c8b4bc..ff91fc3804 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -421,6 +421,18 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, if (method != nullptr) { if (verifier.HasInstructionThatWillThrow()) { method->AddAccessFlags(kAccCompileDontBother); + if (Runtime::Current()->IsAotCompiler() && !callbacks->IsBootImage()) { + // When compiling apps, make HasInstructionThatWillThrow a soft error to trigger + // re-verification at runtime. + // The dead code after the throw is not verified and might be invalid. This may cause + // the JIT compiler to crash since it assumes that all the code is valid. + // + // There's a strong assumption that the entire boot image is verified and all its dex + // code is valid (even the dead and unverified one). As such this is done only for apps. + // (CompilerDriver DCHECKs in VerifyClassVisitor that methods from boot image are + // fully verified). + result.kind = kSoftFailure; + } } if ((verifier.encountered_failure_types_ & VerifyError::VERIFY_ERROR_LOCKING) != 0) { method->AddAccessFlags(kAccMustCountLocks); diff --git a/test/706-jit-skip-compilation/expected.txt b/test/706-jit-skip-compilation/expected.txt new file mode 100644 index 0000000000..6a5618ebc6 --- /dev/null +++ b/test/706-jit-skip-compilation/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/706-jit-skip-compilation/info.txt b/test/706-jit-skip-compilation/info.txt new file mode 100644 index 0000000000..e9ef86bfb3 --- /dev/null +++ b/test/706-jit-skip-compilation/info.txt @@ -0,0 +1,4 @@ +Regression test for the JIT crashing when compiling a method with invalid +dead dex code. For not compilable methods we don't gather samples and we don't +trigger JIT compilation. However kAccDontBotherCompile is not persisted in the +oat file and so we may end up compiling a method which we shouldn't. diff --git a/test/706-jit-skip-compilation/run b/test/706-jit-skip-compilation/run new file mode 100644 index 0000000000..6c5720a099 --- /dev/null +++ b/test/706-jit-skip-compilation/run @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Copyright (C) 2016 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. + +# Run without the app image, otherwise the verification results will be cached +# in the ArtMethod of the image and the test will be skewed. +exec ${RUN} "${@}" --no-app-image diff --git a/test/706-jit-skip-compilation/smali/errclass.smali b/test/706-jit-skip-compilation/smali/errclass.smali new file mode 100644 index 0000000000..410504cb2f --- /dev/null +++ b/test/706-jit-skip-compilation/smali/errclass.smali @@ -0,0 +1,34 @@ +# Copyright (C) 2016 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. + + +.class public LErrClass; + +.super Ljava/lang/Object; + +.method public static errMethod()J + .registers 8 + const/4 v0, 0x0 + const/4 v3, 0x0 + aget v1, v0, v3 # v0 is null, this will alays throw and the invalid code + # below will not be verified. + move v3, v4 + move-wide/from16 v6, v2 # should trigger a verification error if verified as + # v3 is a single register but used as a pair here. + return v6 +.end method + +# Add a field to work around demerger bug b/18051191. +# Failure to verify dex file '...': Offset(552) should be zero when size is zero for field-ids. +.field private a:I diff --git a/test/706-jit-skip-compilation/src/Main.java b/test/706-jit-skip-compilation/src/Main.java new file mode 100644 index 0000000000..aa847248d6 --- /dev/null +++ b/test/706-jit-skip-compilation/src/Main.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 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 java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class Main { + public static void main(String[] args) throws Exception { + System.loadLibrary(args[0]); + Class<?> c = Class.forName("ErrClass"); + Method m = c.getMethod("errMethod"); + + // Print the counter before invokes. The golden file expects this to be 0. + int hotnessCounter = getHotnessCounter(c, "errMethod"); + if (hotnessCounter != 0) { + throw new RuntimeException("Unexpected hotnessCounter: " + hotnessCounter); + } + + // Loop enough to make sure the interpreter reports invocations count. + long result = 0; + for (int i = 0; i < 10000; i++) { + try { + result += (Long)m.invoke(null); + hotnessCounter = getHotnessCounter(c, "errMethod"); + if (hotnessCounter != 0) { + throw new RuntimeException( + "Unexpected hotnessCounter: " + hotnessCounter); + } + + } catch (InvocationTargetException e) { + if (!(e.getCause() instanceof NullPointerException)) { + throw e; + } + } + } + + // Not compilable methods should not increase their hotness counter. + if (hotnessCounter != 0) { + throw new RuntimeException("Unexpected hotnessCounter: " + hotnessCounter); + } + } + + public static native int getHotnessCounter(Class cls, String method_name); +} diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc index 285f3aa541..f26e122580 100644 --- a/test/common/runtime_state.cc +++ b/test/common/runtime_state.cc @@ -188,4 +188,28 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasSingleImplementation(JNIEnv* return method->HasSingleImplementation(); } +extern "C" JNIEXPORT int JNICALL Java_Main_getHotnessCounter(JNIEnv* env, + jclass, + jclass cls, + jstring method_name) { + jit::Jit* jit = Runtime::Current()->GetJit(); + if (jit == nullptr) { + // The hotness counter is valid only under JIT. + // If we don't JIT return 0 to match test expectations. + return 0; + } + + ArtMethod* method = nullptr; + { + ScopedObjectAccess soa(Thread::Current()); + + ScopedUtfChars chars(env, method_name); + CHECK(chars.c_str() != nullptr); + method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName( + chars.c_str(), kRuntimePointerSize); + } + + return method->GetCounter(); +} + } // namespace art diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index f3958662df..566f7ba522 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -59,6 +59,7 @@ ARGS="" EXTERNAL_LOG_TAGS="n" # if y respect externally set ANDROID_LOG_TAGS. DRY_RUN="n" # if y prepare to run the test but don't run it. TEST_VDEX="n" +APP_IMAGE="y" while true; do if [ "x$1" = "x--quiet" ]; then @@ -132,6 +133,9 @@ while true; do elif [ "x$1" = "x--prebuild" ]; then PREBUILD="y" shift + elif [ "x$1" = "x--no-app-image" ]; then + APP_IMAGE="n" + shift elif [ "x$1" = "x--strip-dex" ]; then STRIP_DEX="y" shift @@ -453,11 +457,14 @@ vdex_cmdline="true" mkdir_locations="${DEX_LOCATION}/dalvik-cache/$ISA" strip_cmdline="true" -# Pick a base that will force the app image to get relocated. -app_image="--base=0x4000 --app-image-file=$DEX_LOCATION/oat/$ISA/$TEST_NAME.art" if [ "$PREBUILD" = "y" ]; then mkdir_locations="${mkdir_locations} ${DEX_LOCATION}/oat/$ISA" + if [ "$APP_IMAGE" = "y" ]; then + # Pick a base that will force the app image to get relocated. + app_image="--base=0x4000 --app-image-file=$DEX_LOCATION/oat/$ISA/$TEST_NAME.art" + fi + dex2oat_cmdline="$INVOKE_WITH $ANDROID_ROOT/bin/dex2oatd \ $COMPILE_FLAGS \ --boot-image=${BOOT_IMAGE} \ |