From: Andreas Gampe Date: Thu, 25 Jun 2015 17:26:40 +0000 (-0700) Subject: ART: Reset runtime_throw_failure flag X-Git-Tag: android-x86-6.0-r1~61 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=6415013f;p=android-x86%2Fart.git ART: Reset runtime_throw_failure flag The flag is instruction-specific. It transports the info from Fail to the main loop. It must be cleared after each iteration. Introduce a second flag to store whether we saw such a failure at all. Update test expectations. Bug: 22080519 (cherry picked from commit d12e782bcee03ecb6dec41aa9673ef53b638dcea) Change-Id: I32be914819946233babaa4cb7343844d97b61ba5 --- diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 89f51158d..1f7dd58d3 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -400,6 +400,7 @@ MethodVerifier::MethodVerifier(Thread* self, monitor_enter_dex_pcs_(nullptr), have_pending_hard_failure_(false), have_pending_runtime_throw_failure_(false), + have_any_pending_runtime_throw_failure_(false), new_instance_count_(0), monitor_enter_count_(0), can_load_classes_(can_load_classes), @@ -1636,6 +1637,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { } else if (kIsDebugBuild) { saved_line_->FillWithGarbage(); } + DCHECK(!have_pending_runtime_throw_failure_); // Per-instruction flag, should not be set here. // We need to ensure the work line is consistent while performing validation. When we spot a @@ -2936,6 +2938,10 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { } else if (have_pending_runtime_throw_failure_) { /* checking interpreter will throw, mark following code as unreachable */ opcode_flags = Instruction::kThrow; + have_any_pending_runtime_throw_failure_ = true; + // Reset the pending_runtime_throw flag. The flag is a global to decouple Fail and is per + // instruction. + have_pending_runtime_throw_failure_ = false; } /* * If we didn't just set the result register, clear it out. This ensures that you can only use diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 204b18e12..62800fbc6 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -245,7 +245,7 @@ class MethodVerifier { bool HasVirtualOrInterfaceInvokes() const; bool HasFailures() const; bool HasInstructionThatWillThrow() const { - return have_pending_runtime_throw_failure_; + return have_any_pending_runtime_throw_failure_; } const RegType& ResolveCheckedClass(uint32_t class_idx) @@ -720,8 +720,12 @@ class MethodVerifier { // would fail at runtime throwing an exception. Such an instruction causes the following code // to be unreachable. This is set by Fail and used to ensure we don't process unreachable // instructions that would hard fail the verification. + // Note: this flag is reset after processing each instruction. bool have_pending_runtime_throw_failure_; + // A version of the above that is not reset and thus captures if there were *any* throw failures. + bool have_any_pending_runtime_throw_failure_; + // Info message log use primarily for verifier diagnostics. std::ostringstream info_messages_; diff --git a/test/003-omnibus-opcodes/src/UnresTest2.java b/test/003-omnibus-opcodes/src/UnresTest2.java index 4135d73f7..d46b877dd 100644 --- a/test/003-omnibus-opcodes/src/UnresTest2.java +++ b/test/003-omnibus-opcodes/src/UnresTest2.java @@ -41,7 +41,8 @@ class UnresTest2 { new UnresClassSubclass(); Main.assertTrue(false); } catch (NoClassDefFoundError ncdfe) { - Main.assertTrue(ncdfe.getCause() instanceof ClassNotFoundException); + // TODO b/22080519 + // Main.assertTrue(ncdfe.getCause() instanceof ClassNotFoundException); // good } @@ -49,7 +50,6 @@ class UnresTest2 { UnresClass[] uar = new UnresClass[3]; Main.assertTrue(false); } catch (NoClassDefFoundError ncdfe) { - Main.assertTrue(ncdfe.getCause() instanceof ClassNotFoundException); // good } diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt index ca4ca3534..80b4f5768 100644 --- a/test/800-smali/expected.txt +++ b/test/800-smali/expected.txt @@ -21,4 +21,5 @@ b/21614284 b/21902684 b/21863767 b/21886894 +b/22080519 Done! diff --git a/test/800-smali/smali/b_22080519.smali b/test/800-smali/smali/b_22080519.smali new file mode 100644 index 000000000..bf062fb54 --- /dev/null +++ b/test/800-smali/smali/b_22080519.smali @@ -0,0 +1,27 @@ +.class public LB22080519; +.super Ljava/lang/Object; + +.method public static run()V +.registers 6 +:Label1 + const v1, 15 + const v2, 0 + # Have a branch to reach both the aget-object and something else. + if-eqz v1, :Label2 + + # This instruction will be marked runtime-throw. + aget-object v3, v2, v1 + +:Label2 + # This should *not* be flagged as a runtime throw + goto :Label4 + +:Label3 + move-exception v3 + throw v3 + +:Label4 + return-void + +.catchall {:Label1 .. :Label3} :Label3 +.end method \ No newline at end of file diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java index 8c9fda118..337d0d994 100644 --- a/test/800-smali/src/Main.java +++ b/test/800-smali/src/Main.java @@ -83,12 +83,14 @@ public class Main { 0)); testCases.add(new TestCase("b/21873167", "B21873167", "test", null, null, null)); testCases.add(new TestCase("b/21614284", "B21614284", "test", new Object[] { null }, - new NullPointerException(), null)); + new NullPointerException(), null)); testCases.add(new TestCase("b/21902684", "B21902684", "test", null, null, null)); testCases.add(new TestCase("b/21863767", "B21863767", "run", null, null, null)); testCases.add(new TestCase("b/21886894", "B21886894", "test", null, new VerifyError(), - null)); + null)); + testCases.add(new TestCase("b/22080519", "B22080519", "run", null, + new NullPointerException(), null)); } public void runTests() {