summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Alexey Grebenkin <a.grebenkin@samsung.com> 2018-05-31 23:42:20 +0300
committer Alexey Grebenkin <a.grebenkin@samsung.com> 2018-07-13 17:07:25 +0300
commitce75049c31e7064b00104ca7f65fe12faeabc391 (patch)
tree6f7bb5977a99db0d89c74238576956f0aa1d4dad
parent0495fb053094181de232e3fa390806a9110ba208 (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.cc39
-rw-r--r--test/800-smali/expected.txt2
-rw-r--r--test/800-smali/jni.cc41
-rw-r--r--test/800-smali/smali/ConstClassAliasing.smali12
-rw-r--r--test/800-smali/src/Main.java22
-rw-r--r--test/Android.bp1
-rw-r--r--test/common/runtime_state.cc6
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;
}
}