diff options
| author | 2018-05-31 23:42:20 +0300 | |
|---|---|---|
| committer | 2018-07-13 17:07:25 +0300 | |
| commit | ce75049c31e7064b00104ca7f65fe12faeabc391 (patch) | |
| tree | 6f7bb5977a99db0d89c74238576956f0aa1d4dad | |
| parent | 0495fb053094181de232e3fa390806a9110ba208 (diff) | |
Revert "Revert "Handle a special case of lock aliasing during lock verification""
This reverts commit 753a055b5398fcf00d2633565452679c8fb93e9d.
Reason for revert: Fixed failing tests
Test: m test-art-host
Change-Id: I4a8be656288199108c05c9d302393e1efa41a7a4
| -rw-r--r-- | runtime/verifier/method_verifier.cc | 39 | ||||
| -rw-r--r-- | test/800-smali/expected.txt | 2 | ||||
| -rw-r--r-- | test/800-smali/jni.cc | 41 | ||||
| -rw-r--r-- | test/800-smali/smali/ConstClassAliasing.smali | 12 | ||||
| -rw-r--r-- | test/800-smali/src/Main.java | 22 | ||||
| -rw-r--r-- | test/Android.bp | 1 | ||||
| -rw-r--r-- | test/common/runtime_state.cc | 6 |
7 files changed, 121 insertions, 2 deletions
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 47877bd195..77105a8603 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -2254,6 +2254,45 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { } break; + // Catch a case of register aliasing when two registers are linked to the same + // java.lang.Class object via two consequent const-class instructions immediately + // preceding monitor-enter called on one of those registers. + case Instruction::CONST_CLASS: { + // Get the second previous instruction. + if (prev_idx == 0 || GetInstructionFlags(prev_idx).IsBranchTarget()) { + break; + } + prev_idx--; + while (0 != prev_idx && !GetInstructionFlags(prev_idx).IsOpcode()) { + prev_idx--; + } + const Instruction& prev2_inst = code_item_accessor_.InstructionAt(prev_idx); + + // Match the pattern "const-class; const-class; monitor-enter;" + if (prev2_inst.Opcode() != Instruction::CONST_CLASS) { + break; + } + + // Ensure both const-classes are called for the same type_idx. + if (prev_inst.VRegB_21c() != prev2_inst.VRegB_21c()) { + break; + } + + // Update the lock status for the aliased register. + if (prev_inst.VRegA() == inst->VRegA_11x()) { + work_line_->CopyRegister1(this, + prev2_inst.VRegA(), + inst->VRegA_11x(), + kTypeCategoryRef); + } else if (prev2_inst.VRegA() == inst->VRegA_11x()) { + work_line_->CopyRegister1(this, + prev_inst.VRegA(), + inst->VRegA_11x(), + kTypeCategoryRef); + } + break; + } + default: // Other instruction types ignored. break; } diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt index b8324e54e3..f3c3f03a9a 100644 --- a/test/800-smali/expected.txt +++ b/test/800-smali/expected.txt @@ -1,3 +1,4 @@ +JNI_OnLoad called PackedSwitch PackedSwitch key INT_MAX PackedSwitch key overflow @@ -71,4 +72,5 @@ b/29778499 (1) b/29778499 (2) b/30458218 b/31313170 +ConstClassAliasing Done! diff --git a/test/800-smali/jni.cc b/test/800-smali/jni.cc new file mode 100644 index 0000000000..bf9e88ab45 --- /dev/null +++ b/test/800-smali/jni.cc @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 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 "jni.h" + +#include "class_linker-inl.h" +#include "dex/dex_file-inl.h" +#include "mirror/class-inl.h" +#include "mirror/dex_cache-inl.h" +#include "runtime.h" +#include "scoped_thread_state_change-inl.h" + +namespace art { +namespace { + +extern "C" JNIEXPORT jboolean JNICALL Java_Main_isAotVerified(JNIEnv* env, jclass, jclass cls) { + ScopedObjectAccess soa(env); + Runtime* rt = Runtime::Current(); + + ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls); + const DexFile& dex_file = *klass->GetDexCache()->GetDexFile(); + ClassStatus oat_file_class_status(ClassStatus::kNotReady); + bool ret = rt->GetClassLinker()->VerifyClassUsingOatFile(dex_file, klass, oat_file_class_status); + return ret; +} + +} // namespace +} // namespace art diff --git a/test/800-smali/smali/ConstClassAliasing.smali b/test/800-smali/smali/ConstClassAliasing.smali new file mode 100644 index 0000000000..a65d9a7a5d --- /dev/null +++ b/test/800-smali/smali/ConstClassAliasing.smali @@ -0,0 +1,12 @@ +.class public LConstClassAliasing; + +.super Ljava/lang/Object; + +.method public static run()V + .registers 2 + const-class v0, Ljava/lang/Object; + const-class v1, Ljava/lang/Object; + monitor-enter v0 + monitor-exit v1 + return-void +.end method diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java index 8d39f0971f..9b06e9edda 100644 --- a/test/800-smali/src/Main.java +++ b/test/800-smali/src/Main.java @@ -27,13 +27,21 @@ public class Main { private static class TestCase { public TestCase(String testName, String testClass, String testMethodName, Object[] values, - Throwable expectedException, Object expectedReturn) { + Throwable expectedException, Object expectedReturn, + boolean checkCompiled) { this.testName = testName; this.testClass = testClass; this.testMethodName = testMethodName; this.values = values; this.expectedException = expectedException; this.expectedReturn = expectedReturn; + this.checkCompiled = checkCompiled; + } + + public TestCase(String testName, String testClass, String testMethodName, Object[] values, + Throwable expectedException, Object expectedReturn) { + this(testName, testClass, testMethodName, values, expectedException, + expectedReturn, false); } String testName; @@ -42,6 +50,7 @@ public class Main { Object[] values; Throwable expectedException; Object expectedReturn; + boolean checkCompiled; } private List<TestCase> testCases; @@ -182,6 +191,8 @@ public class Main { new IncompatibleClassChangeError(), null)); testCases.add(new TestCase("b/30458218", "B30458218", "run", null, null, null)); testCases.add(new TestCase("b/31313170", "B31313170", "run", null, null, 0)); + testCases.add(new TestCase("ConstClassAliasing", "ConstClassAliasing", "run", null, null, + null, true)); } public void runTests() { @@ -235,6 +246,10 @@ public class Main { errorReturn = new IllegalStateException("Expected return " + tc.expectedReturn + ", but got " + retValue); + } else if (tc.checkCompiled && compiledWithOptimizing() && !isAotVerified(c)) { + errorReturn = new IllegalStateException("Expected method " + method.getName() + + " of class " + c.getName() + + " be verified in compile-time in test " + tc.testName); } else { // Expected result, do nothing. } @@ -260,10 +275,15 @@ public class Main { } public static void main(String[] args) throws Exception { + System.loadLibrary(args[0]); + Main main = new Main(); main.runTests(); System.out.println("Done!"); } + + private native static boolean isAotVerified(Class<?> cls); + private native static boolean compiledWithOptimizing(); } diff --git a/test/Android.bp b/test/Android.bp index e205b7583a..5d2ea1aa7f 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -488,6 +488,7 @@ cc_defaults { "667-jit-jni-stub/jit_jni_stub_test.cc", "674-hiddenapi/hiddenapi.cc", "708-jit-cache-churn/jit.cc", + "800-smali/jni.cc", "909-attach-agent/disallow_debugging.cc", "1947-breakpoint-redefine-deopt/check_deopt.cc", "common/runtime_state.cc", diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc index bd63389da3..9344b24b5d 100644 --- a/test/common/runtime_state.cc +++ b/test/common/runtime_state.cc @@ -132,9 +132,13 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_compiledWithOptimizing(JNIEnv* e constexpr const char* kInterpretOnly = "interpret-only"; constexpr const char* kVerifyNone = "verify-none"; constexpr const char* kVerifyAtRuntime = "verify-at-runtime"; + constexpr const char* kQuicken = "quicken"; + constexpr const char* kExtract = "extract"; if (strncmp(filter, kInterpretOnly, strlen(kInterpretOnly)) == 0 || strncmp(filter, kVerifyNone, strlen(kVerifyNone)) == 0 || - strncmp(filter, kVerifyAtRuntime, strlen(kVerifyAtRuntime)) == 0) { + strncmp(filter, kVerifyAtRuntime, strlen(kVerifyAtRuntime)) == 0 || + strncmp(filter, kExtract, strlen(kExtract)) == 0 || + strncmp(filter, kQuicken, strlen(kQuicken)) == 0) { return JNI_FALSE; } } |