Revert^2: Deopt does not throw

Rationale:
"CanThrow" of deopt was possibly misused to prevents some
optimizations. However, the instruction technically cannot
throw an exception, and indeed crashed the graph verifier
for some corner cases. This Cl sets that right.

Bug: 29868356

Test: test-art-host,target

(revert^2 of commit 2905de1c0e5b6a0c995be474b3f0efdfdc6a41c4)

Change-Id: I4d4e6c00eff52140aa1845332998224ececc92ef
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index f784f8f..79bb70b 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -1916,15 +1916,6 @@
   }
 }
 
-bool HBasicBlock::HasThrowingInstructions() const {
-  for (HInstructionIterator it(GetInstructions()); !it.Done(); it.Advance()) {
-    if (it.Current()->CanThrow()) {
-      return true;
-    }
-  }
-  return false;
-}
-
 static bool HasOnlyOneInstruction(const HBasicBlock& block) {
   return block.GetPhis().IsEmpty()
       && !block.GetInstructions().IsEmpty()
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 79d7330..b315c81 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1272,8 +1272,6 @@
   // the appropriate try entry will be returned.
   const HTryBoundary* ComputeTryEntryOfSuccessors() const;
 
-  bool HasThrowingInstructions() const;
-
   // Returns whether this block dominates the blocked passed as parameter.
   bool Dominates(HBasicBlock* block) const;
 
@@ -2132,6 +2130,7 @@
         !CanThrow() &&
         !IsSuspendCheck() &&
         !IsControlFlow() &&
+        !IsDeoptimize() &&
         !IsNativeDebugInfo() &&
         !IsParameterValue() &&
         // If we added an explicit barrier then we should keep it.
@@ -3238,7 +3237,9 @@
 
   bool NeedsEnvironment() const OVERRIDE { return true; }
 
-  bool CanThrow() const OVERRIDE { return true; }
+  // Even though deoptimize is often used for "exceptional cases" to go back to
+  // the interpreter, it never throws an exception.
+  bool CanThrow() const OVERRIDE { return false; }
 
   DeoptimizationKind GetDeoptimizationKind() const { return GetPackedField<DeoptimizeKindField>(); }
 
diff --git a/test/683-deopt-regression/expected.txt b/test/683-deopt-regression/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/683-deopt-regression/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/683-deopt-regression/info.txt b/test/683-deopt-regression/info.txt
new file mode 100644
index 0000000..0c2cb81
--- /dev/null
+++ b/test/683-deopt-regression/info.txt
@@ -0,0 +1 @@
+Regression test on deopt from BCE
diff --git a/test/683-deopt-regression/smali/Deopt.smali b/test/683-deopt-regression/smali/Deopt.smali
new file mode 100644
index 0000000..3bd9f6c
--- /dev/null
+++ b/test/683-deopt-regression/smali/Deopt.smali
@@ -0,0 +1,60 @@
+# 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.
+
+.class public LDeopt;
+
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+.registers 1
+    invoke-direct {v0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public static testCase([I)I
+    .registers 8
+
+    const v0, 0x0          # counter
+    const v1, 0xF          # loop max
+    const v2, 0x0          # result
+
+    :try_start
+    # Something throwing to start the try block. v6 contains a reference.
+    move-object v6, p0
+    aget v3, p0, v0
+
+    # Invalidate v6 before entering the loop.
+    const-wide v5, 0x0
+
+    :loop_start
+    # Set v6 to a different reference (creates a catch phi).
+    const v6, 0x0
+
+    aget v3, p0, v0
+    add-int/2addr v2, v3
+    add-int/lit8 v0, v0, 0x1
+    if-lt v0, v1, :loop_start
+
+    :try_end
+    .catchall {:try_start .. :try_end} :catch
+
+    :exit
+    return v2
+
+    :catch
+    invoke-virtual {v6}, Ljava/lang/Object;->hashCode()I   # use v6 as a reference
+    goto :exit
+
+.end method
+
diff --git a/test/683-deopt-regression/src/Main.java b/test/683-deopt-regression/src/Main.java
new file mode 100644
index 0000000..326fe47
--- /dev/null
+++ b/test/683-deopt-regression/src/Main.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+import java.lang.reflect.Method;
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    if (System.getProperty("java.vm.name").equals("Dalvik")) {
+      Class<?> c = Class.forName("Deopt");
+      Method m = c.getMethod("testCase", int[].class);
+      int[] p = null;
+      try {
+        m.invoke(null, p);
+        System.out.println("should not reach");
+      } catch (Exception e) {
+        // Tried to invoke hashCode on incoming null.
+      }
+      int result;
+      int[] q = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+      result = ((Integer) m.invoke(null, q));
+      expectEquals(120, result);
+      int[] r = { };
+      result = ((Integer) m.invoke(null, r));
+      expectEquals(0, result);
+      int[] s = { 1 };
+      try {
+        m.invoke(null, s);
+        System.out.println("should not reach");
+      } catch (Exception e) {
+        // Tried to invoke hashCode on generated null.
+      }
+    }
+    System.out.println("passed");
+  }
+
+  private static void expectEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+}