Revert^2 "Add support for try catches in LSE"

This reverts commit 2913ddad8b7f6e2ff7c92347ee8f67346cdfb16f.

Reason for revert: Updated tests

Bug: 227283233
Change-Id: Ied1e47b9cb55c2a39862e479b754f827e37e6303
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index d42e4f7..4651210 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -78,6 +78,8 @@
  *    all back-edges. We use Phi placeholders also for array heap locations with
  *    index defined inside the loop but this helps only when the value remains
  *    zero from the array allocation throughout the loop.
+ *  - For catch blocks, we clear all assumptions since we arrived due to an
+ *    instruction throwing.
  *  - For other basic blocks, we merge incoming values from the end of all
  *    predecessors. If any incoming value is unknown, the start value for this
  *    block is also unknown. Otherwise, if all the incoming values are the same
@@ -113,8 +115,6 @@
  *  - SIMD graphs (with VecLoad and VecStore instructions) are also handled. Any
  *    partial overlap access among ArrayGet/ArraySet/VecLoad/Store is seen as
  *    alias and no load/store is eliminated in such case.
- *  - Currently this LSE algorithm doesn't handle graph with try-catch, due to
- *    the special block merging structure.
  *
  * The time complexity of the initial phase has several components. The total
  * time for the initialization of heap values for all blocks is
@@ -1618,8 +1618,9 @@
   ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[block->GetBlockId()];
   DCHECK(heap_values.empty());
   size_t num_heap_locations = heap_location_collector_.GetNumberOfHeapLocations();
-  if (block->GetPredecessors().empty()) {
-    DCHECK(block->IsEntryBlock());
+  if (block->GetPredecessors().empty() || (block->GetTryCatchInformation() != nullptr &&
+                                           block->GetTryCatchInformation()->IsCatchBlock())) {
+    DCHECK_IMPLIES(block->GetPredecessors().empty(), block->IsEntryBlock());
     heap_values.resize(num_heap_locations,
                        {/*value=*/Value::PureUnknown(), /*stored_by=*/Value::PureUnknown()});
     return;
@@ -3877,9 +3878,8 @@
 };
 
 bool LoadStoreElimination::Run(bool enable_partial_lse) {
-  if (graph_->IsDebuggable() || graph_->HasTryCatch()) {
+  if (graph_->IsDebuggable()) {
     // Debugger may set heap values or trigger deoptimization of callers.
-    // Try/catch support not implemented yet.
     // Skip this optimization.
     return false;
   }
diff --git a/test/004-ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
index 4317b5d..0659c0b 100644
--- a/test/004-ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
@@ -52,7 +52,6 @@
     // we know the Dex registers with live reference values. Assert that what we
     // find is what is expected.
     if (m_name.compare("f") == 0) {
-      CHECK_REGS_CONTAIN_REFS(0x03U, true, 8);  // v8: this
       CHECK_REGS_CONTAIN_REFS(0x06U, true, 8, 1);  // v8: this, v1: x
       CHECK_REGS_CONTAIN_REFS(0x0cU, true, 8, 3, 1);  // v8: this, v3: y, v1: x
       CHECK_REGS_CONTAIN_REFS(0x10U, true, 8, 3, 1);  // v8: this, v3: y, v1: x
diff --git a/test/061-out-of-memory/src/Main.java b/test/061-out-of-memory/src/Main.java
index bda978e..a9d5593 100644
--- a/test/061-out-of-memory/src/Main.java
+++ b/test/061-out-of-memory/src/Main.java
@@ -23,25 +23,25 @@
 public class Main {
     public static void main(String args[]) {
         System.out.println("tests beginning");
-        testHugeArray();
-        testOomeLarge();
-        testOomeSmall();
-        testOomeToCharArray();
+        $noinline$testHugeArray();
+        $noinline$testOomeLarge();
+        $noinline$testOomeSmall();
+        $noinline$testOomeToCharArray();
         System.out.println("tests succeeded");
     }
 
-    private static void testHugeArray() {
+    private static int[] $noinline$testHugeArray() {
+        int[] tooBig = null;
         try {
             final int COUNT = 32768*32768 + 4;
-            int[] tooBig = new int[COUNT];
-
-            Arrays.fill(tooBig, 0xdd);
+            tooBig = new int[COUNT];
         } catch (OutOfMemoryError oom) {
             System.out.println("Got expected huge-array OOM");
         }
+        return tooBig;
     }
 
-    private static void testOomeLarge() {
+    private static void $noinline$testOomeLarge() {
         System.out.println("testOomeLarge beginning");
 
         Boolean sawEx = false;
@@ -52,7 +52,6 @@
             // try to allocate it instead of short-circuiting.
             a = new byte[(int) Runtime.getRuntime().maxMemory() - 32];
         } catch (OutOfMemoryError oom) {
-            //Log.i(TAG, "HeapTest/OomeLarge caught " + oom);
             sawEx = true;
         }
 
@@ -96,7 +95,7 @@
         return true;
     }
 
-    private static void testOomeSmall() {
+    private static void $noinline$testOomeSmall() {
         System.out.println("testOomeSmall beginning");
         if (!testOomeSmallInternal()) {
             /* Can't reliably throw this from inside the internal function, because
@@ -108,7 +107,7 @@
         System.out.println("testOomeSmall succeeded");
     }
 
-    private static void testOomeToCharArray() {
+    private static Object $noinline$testOomeToCharArray() {
         Object[] o = new Object[2000000];
         String test = "test";
         int i = 0;
@@ -123,5 +122,6 @@
             o = null;
             System.out.println("Got expected toCharArray OOM");
         }
+        return o;
     }
 }
diff --git a/test/510-checker-try-catch/src/Main.java b/test/510-checker-try-catch/src/Main.java
index 5d1d2d8..2877ef8 100644
--- a/test/510-checker-try-catch/src/Main.java
+++ b/test/510-checker-try-catch/src/Main.java
@@ -45,16 +45,13 @@
   /// CHECK-DAG: <<ArrayA:l\d+>>       ParameterValue
   /// CHECK-DAG: <<ArrayB:l\d+>>       ParameterValue
   //
-
   /// CHECK-DAG: <<NullCh1:l\d+>>      NullCheck [<<ArrayA>>]
   /// CHECK-DAG: <<LengthA:i\d+>>      ArrayLength
   /// CHECK-DAG: <<BoundsCh1:i\d+>>    BoundsCheck [<<IndexParam>>,<<LengthA>>]
-  /// CHECK-DAG: <<IntAddr1:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
-  /// CHECK-DAG:                       ArraySet [<<IntAddr1>>,<<BoundsCh1>>,<<Const1>>]
   /// CHECK-DAG:                       TryBoundary
   //
-  /// CHECK-DAG: <<IntAddr2:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
-  /// CHECK-DAG:                       ArraySet [<<IntAddr2>>,<<BoundsCh1>>,<<Const2>>]
+  /// CHECK-DAG: <<IntAddr1:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
+  /// CHECK-DAG:                       ArraySet [<<IntAddr1>>,<<BoundsCh1>>,<<Const2>>]
   /// CHECK-DAG: <<NullChB:l\d+>>      NullCheck [<<ArrayB>>]
   /// CHECK-DAG: <<LengthB:i\d+>>      ArrayLength
   /// CHECK-DAG: <<BoundsChB:i\d+>>    BoundsCheck [<<Const0>>,<<LengthB>>]
@@ -63,13 +60,13 @@
   /// CHECK-DAG: <<Div:i\d+>>          Div [<<GetB>>,<<ZeroCheck>>]
   /// CHECK-DAG: <<Xplus1:i\d+>>       Add [<<IndexParam>>,<<Const1>>]
   /// CHECK-DAG: <<BoundsCh2:i\d+>>    BoundsCheck [<<Xplus1>>,<<LengthA>>]
-  /// CHECK-DAG: <<IntAddr3:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
-  /// CHECK-DAG:                       ArraySet [<<IntAddr3>>,<<BoundsCh2>>,<<Div>>]
+  /// CHECK-DAG: <<IntAddr2:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
+  /// CHECK-DAG:                       ArraySet [<<IntAddr2>>,<<BoundsCh2>>,<<Div>>]
   /// CHECK-DAG:                       TryBoundary
   //
   /// CHECK-DAG:                       ClearException
-  /// CHECK-DAG: <<IntAddr4:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
-  /// CHECK-DAG:                       ArraySet [<<IntAddr4>>,<<BoundsCh1>>,<<Const1>>]
+  /// CHECK-DAG: <<IntAddr3:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
+  /// CHECK-DAG:                       ArraySet [<<IntAddr3>>,<<BoundsCh1>>,<<Const1>>]
   //
   /// CHECK-NOT:                       NullCheck
   /// CHECK-NOT:                       IntermediateAddress
@@ -86,10 +83,9 @@
   /// CHECK-DAG: <<NullCh1:l\d+>>      NullCheck [<<ArrayA>>]
   /// CHECK-DAG: <<LengthA:i\d+>>      ArrayLength
   /// CHECK-DAG: <<BoundsCh1:i\d+>>    BoundsCheck [<<IndexParam>>,<<LengthA>>]
-  /// CHECK-DAG: <<IntAddr1:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
-  /// CHECK-DAG:                       ArraySet [<<IntAddr1>>,<<BoundsCh1>>,<<Const1>>]
   /// CHECK-DAG:                       TryBoundary
   //
+  /// CHECK-DAG: <<IntAddr1:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
   /// CHECK-DAG:                       ArraySet [<<IntAddr1>>,<<BoundsCh1>>,<<Const2>>]
   /// CHECK-DAG: <<NullChB:l\d+>>      NullCheck [<<ArrayB>>]
   /// CHECK-DAG: <<LengthB:i\d+>>      ArrayLength
@@ -103,14 +99,16 @@
   /// CHECK-DAG:                       TryBoundary
   //
   /// CHECK-DAG:                       ClearException
-  /// CHECK-DAG: <<IntAddr4:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
-  /// CHECK-DAG:                       ArraySet [<<IntAddr4>>,<<BoundsCh1>>,<<Const1>>]
+  /// CHECK-DAG: <<IntAddr3:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
+  /// CHECK-DAG:                       ArraySet [<<IntAddr3>>,<<BoundsCh1>>,<<Const1>>]
   //
   /// CHECK-NOT:                       NullCheck
   /// CHECK-NOT:                       IntermediateAddress
 
   //  Make sure that BoundsCheck, DivZeroCheck and NullCheck don't stop IntermediateAddress sharing.
   public static void boundsCheckAndCatch(int x, int[] a, int[] b) {
+    // This a[x] = 1 will be eliminated by LSE, but its related instructions (e.g. NullCheck and
+    // BoundsCheck) will remain.
     a[x] = 1;
     try {
       a[x] = 2;
diff --git a/test/530-checker-lse-try-catch/expected-stderr.txt b/test/530-checker-lse-try-catch/expected-stderr.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/530-checker-lse-try-catch/expected-stderr.txt
diff --git a/test/530-checker-lse-try-catch/expected-stdout.txt b/test/530-checker-lse-try-catch/expected-stdout.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/530-checker-lse-try-catch/expected-stdout.txt
diff --git a/test/530-checker-lse-try-catch/info.txt b/test/530-checker-lse-try-catch/info.txt
new file mode 100644
index 0000000..9ceef82
--- /dev/null
+++ b/test/530-checker-lse-try-catch/info.txt
@@ -0,0 +1 @@
+Checker test for testing load-store elimination for try catches.
diff --git a/test/530-checker-lse-try-catch/src/Main.java b/test/530-checker-lse-try-catch/src/Main.java
new file mode 100644
index 0000000..c7db02a
--- /dev/null
+++ b/test/530-checker-lse-try-catch/src/Main.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2022 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 Point {
+  int x;
+  int y;
+}
+
+public class Main {
+  public static void main(String[] args) {
+    final boolean boolean_throw = false;
+    final boolean boolean_other_throw = false;
+    assertEquals(3,
+        $noinline$testDifferentFields(
+            new Point(), new Point(), boolean_throw, boolean_other_throw));
+    assertEquals(1, $noinline$testRedundantStore(new Point(), boolean_throw, boolean_other_throw));
+    assertEquals(1, $noinline$testTryCatchBlocking(new Point(), boolean_throw));
+    assertEquals(1, $noinline$testTryCatchPhi(new Point(), boolean_throw));
+    assertEquals(2, $noinline$testTryCatchPhiWithTwoCatches(new Point(), new int[0]));
+  }
+
+  /// CHECK-START: int Main.$noinline$testDifferentFields(Point, Point, boolean, boolean) load_store_elimination (before)
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.x
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.y
+  /// CHECK-DAG:     InstanceFieldGet field_name:Point.x
+  /// CHECK-DAG:     InstanceFieldGet field_name:Point.y
+
+  /// CHECK-START: int Main.$noinline$testDifferentFields(Point, Point, boolean, boolean) load_store_elimination (after)
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.x
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.y
+
+  /// CHECK-START: int Main.$noinline$testDifferentFields(Point, Point, boolean, boolean) load_store_elimination (after)
+  /// CHECK-NOT:     InstanceFieldGet field_name:Point.x
+  /// CHECK-NOT:     InstanceFieldGet field_name:Point.y
+
+  // Consistency check to make sure the try/catches weren't removed by an earlier pass.
+  /// CHECK-START: int Main.$noinline$testDifferentFields(Point, Point, boolean, boolean) load_store_elimination (after)
+  /// CHECK:         TryBoundary kind:entry
+  /// CHECK:         TryBoundary kind:entry
+
+  // Different fields shouldn't alias.
+  private static int $noinline$testDifferentFields(
+      Point obj1, Point obj2, boolean boolean_throw, boolean boolean_other_throw) {
+    try {
+      if (boolean_throw) {
+        throw new Error();
+      }
+    } catch (Error e) {
+      return 0;
+    }
+    obj1.x = 1;
+    obj2.y = 2;
+    int result = obj1.x + obj2.y;
+    try {
+      if (boolean_other_throw) {
+        throw new Error();
+      }
+    } catch (Error e) {
+      return 0;
+    }
+    return result;
+  }
+
+  /// CHECK-START: int Main.$noinline$testRedundantStore(Point, boolean, boolean) load_store_elimination (before)
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.y
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.y
+  /// CHECK-DAG:     InstanceFieldGet field_name:Point.y
+
+  /// CHECK-START: int Main.$noinline$testRedundantStore(Point, boolean, boolean) load_store_elimination (after)
+  /// CHECK:         InstanceFieldSet field_name:Point.y
+  /// CHECK-NOT:     InstanceFieldSet field_name:Point.y
+
+  /// CHECK-START: int Main.$noinline$testRedundantStore(Point, boolean, boolean) load_store_elimination (after)
+  /// CHECK-NOT:     InstanceFieldGet field_name:Point.y
+
+  // Consistency check to make sure the try/catches weren't removed by an earlier pass.
+  /// CHECK-START: int Main.$noinline$testRedundantStore(Point, boolean, boolean) load_store_elimination (after)
+  /// CHECK-DAG:     TryBoundary kind:entry
+  /// CHECK-DAG:     TryBoundary kind:entry
+
+  // Redundant store of the same value.
+  private static int $noinline$testRedundantStore(
+      Point obj, boolean boolean_throw, boolean boolean_other_throw) {
+    try {
+      if (boolean_throw) {
+        throw new Error();
+      }
+    } catch (Error e) {
+      return 0;
+    }
+    obj.y = 1;
+    obj.y = 1;
+    try {
+      if (boolean_other_throw) {
+        throw new Error();
+      }
+    } catch (Error e) {
+      return 0;
+    }
+    return obj.y;
+  }
+
+  /// CHECK-START: int Main.$noinline$testTryCatchBlocking(Point, boolean) load_store_elimination (before)
+  /// CHECK: InstanceFieldSet field_name:Point.y
+  /// CHECK: InstanceFieldGet field_name:Point.y
+
+  /// CHECK-START: int Main.$noinline$testTryCatchBlocking(Point, boolean) load_store_elimination (after)
+  /// CHECK: InstanceFieldSet field_name:Point.y
+  /// CHECK: InstanceFieldGet field_name:Point.y
+
+  // Consistency check to make sure the try/catch wasn't removed by an earlier pass.
+  /// CHECK-START: int Main.$noinline$testTryCatchBlocking(Point, boolean) load_store_elimination (after)
+  /// CHECK: TryBoundary kind:entry
+
+  // We cannot remove the Get since we might have thrown.
+  private static int $noinline$testTryCatchBlocking(Point obj, boolean boolean_throw) {
+    obj.y = 1;
+    try {
+      if (boolean_throw) {
+        throw new Error();
+      }
+    } catch (Error e) {
+    }
+    return obj.y;
+  }
+
+  /// CHECK-START: int Main.$noinline$testTryCatchPhi(Point, boolean) load_store_elimination (before)
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.y
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.y
+  /// CHECK-DAG:     InstanceFieldGet field_name:Point.y
+
+  /// CHECK-START: int Main.$noinline$testTryCatchPhi(Point, boolean) load_store_elimination (after)
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.y
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.y
+
+  /// CHECK-START: int Main.$noinline$testTryCatchPhi(Point, boolean) load_store_elimination (after)
+  /// CHECK-NOT:     InstanceFieldGet field_name:Point.y
+
+  // Consistency check to make sure the try/catch wasn't removed by an earlier pass.
+  /// CHECK-START: int Main.$noinline$testTryCatchPhi(Point, boolean) load_store_elimination (after)
+  /// CHECK-DAG:     TryBoundary kind:entry
+
+  // We either threw and we set the value in the catch, or we didn't throw and we set the value
+  // before the catch. We can solve that with a Phi and skip the get.
+  private static int $noinline$testTryCatchPhi(Point obj, boolean boolean_throw) {
+    obj.y = 1;
+    try {
+      if (boolean_throw) {
+        throw new Error();
+      }
+    } catch (Error e) {
+      obj.y = 2;
+    }
+    return obj.y;
+  }
+
+
+  /// CHECK-START: int Main.$noinline$testTryCatchPhiWithTwoCatches(Point, int[]) load_store_elimination (before)
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.y
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.y
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.y
+  /// CHECK-DAG:     InstanceFieldGet field_name:Point.y
+
+  /// CHECK-START: int Main.$noinline$testTryCatchPhiWithTwoCatches(Point, int[]) load_store_elimination (after)
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.y
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.y
+  /// CHECK-DAG:     InstanceFieldSet field_name:Point.y
+
+  /// CHECK-START: int Main.$noinline$testTryCatchPhiWithTwoCatches(Point, int[]) load_store_elimination (after)
+  /// CHECK-NOT: InstanceFieldGet field_name:Point.y
+
+  // Consistency check to make sure the try/catch wasn't removed by an earlier pass.
+  /// CHECK-START: int Main.$noinline$testTryCatchPhiWithTwoCatches(Point, int[]) load_store_elimination (after)
+  /// CHECK-DAG: TryBoundary kind:entry
+  private static int $noinline$testTryCatchPhiWithTwoCatches(Point obj, int[] numbers) {
+    obj.y = 1;
+    try {
+      if (numbers[0] == 1) {
+        throw new Error();
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      obj.y = 2;
+    } catch (Error e) {
+      obj.y = 3;
+    }
+    return obj.y;
+  }
+
+  private static void assertEquals(int expected, int actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected: " + expected + ", Actual: " + actual);
+    }
+  }
+}
diff --git a/test/639-checker-code-sinking/src/Main.java b/test/639-checker-code-sinking/src/Main.java
index 743d501..5e465f2 100644
--- a/test/639-checker-code-sinking/src/Main.java
+++ b/test/639-checker-code-sinking/src/Main.java
@@ -679,6 +679,11 @@
       }
     } catch (NullPointerException e) {
     }
+
+    // We want to use obj over here so that it doesn't get deleted by LSE.
+    if (obj.x == 123) {
+      return 123;
+    }
     return x;
   }