LSE fix removing observable stores with throwing instuctions

Throwing instructions can make some stores observable that
wouldn't be observable othwerwise.

Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b
Bug: 229706824, 227283233
Change-Id: I03683184db0a2b8c42623fc1148efbec8f5cae11
(cherry picked from commit ea24a14ff37c708360b4cb38baba82af0931d451)
Merged-In: I03683184db0a2b8c42623fc1148efbec8f5cae11
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 827a29f..35cb2a3 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -776,9 +776,6 @@
       "name": "art-run-test-530-checker-lse-simd[com.google.android.art.apex]"
     },
     {
-      "name": "art-run-test-530-checker-lse2[com.google.android.art.apex]"
-    },
-    {
       "name": "art-run-test-530-instanceof-checkcast[com.google.android.art.apex]"
     },
     {
@@ -2071,9 +2068,6 @@
       "name": "art-run-test-530-checker-lse-simd"
     },
     {
-      "name": "art-run-test-530-checker-lse2"
-    },
-    {
       "name": "art-run-test-530-instanceof-checkcast"
     },
     {
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 4651210..e3d8481 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -615,6 +615,11 @@
     return PhiPlaceholderIndex(phi_placeholder.GetPhiPlaceholder());
   }
 
+  bool IsEscapingObject(ReferenceInfo* info, HBasicBlock* block, size_t index) {
+    return !info->IsSingletonAndRemovable() &&
+           !(info->IsPartialSingleton() && IsPartialNoEscape(block, index));
+  }
+
   bool IsPartialNoEscape(HBasicBlock* blk, size_t idx) {
     auto* ri = heap_location_collector_.GetHeapLocation(idx)->GetReferenceInfo();
     if (!ri->IsPartialSingleton()) {
@@ -1035,8 +1040,8 @@
   }
 
   void VisitDeoptimize(HDeoptimize* instruction) override {
-    ScopedArenaVector<ValueRecord>& heap_values =
-        heap_values_for_[instruction->GetBlock()->GetBlockId()];
+    HBasicBlock* block = instruction->GetBlock();
+    ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[block->GetBlockId()];
     for (size_t i = 0u, size = heap_values.size(); i != size; ++i) {
       Value* stored_by = &heap_values[i].stored_by;
       if (stored_by->IsUnknown()) {
@@ -1049,7 +1054,9 @@
       if (info->IsSingleton()) {
         HInstruction* reference = info->GetReference();
         // Finalizable objects always escape.
-        if (!reference->IsNewInstance() || !reference->AsNewInstance()->IsFinalizable()) {
+        const bool finalizable_object =
+            reference->IsNewInstance() && reference->AsNewInstance()->IsFinalizable();
+        if (!finalizable_object && !IsEscapingObject(info, block, i)) {
           // Check whether the reference for a store is used by an environment local of
           // the HDeoptimize. If not, the singleton is not observed after deoptimization.
           const HUseList<HEnvironment*>& env_uses = reference->GetEnvUses();
@@ -1073,8 +1080,7 @@
     ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[block->GetBlockId()];
     for (size_t i = 0u, size = heap_values.size(); i != size; ++i) {
       ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo();
-      if (!ref_info->IsSingletonAndRemovable() &&
-          !(ref_info->IsPartialSingleton() && IsPartialNoEscape(block, i))) {
+      if (IsEscapingObject(ref_info, block, i)) {
         KeepStores(heap_values[i].stored_by);
         heap_values[i].stored_by = Value::PureUnknown();
       }
@@ -1089,11 +1095,64 @@
     HandleExit(return_void->GetBlock());
   }
 
+  void HandleThrowingInstruction(HInstruction* instruction) {
+    DCHECK(instruction->CanThrow());
+    HandleExit(instruction->GetBlock());
+  }
+
+  void VisitMethodEntryHook(HMethodEntryHook* method_entry) override {
+    HandleThrowingInstruction(method_entry);
+  }
+
+  void VisitMethodExitHook(HMethodExitHook* method_exit) override {
+    HandleThrowingInstruction(method_exit);
+  }
+
+  void VisitDivZeroCheck(HDivZeroCheck* div_zero_check) override {
+    HandleThrowingInstruction(div_zero_check);
+  }
+
+  void VisitNullCheck(HNullCheck* null_check) override {
+    HandleThrowingInstruction(null_check);
+  }
+
+  void VisitBoundsCheck(HBoundsCheck* bounds_check) override {
+    HandleThrowingInstruction(bounds_check);
+  }
+
+  void VisitLoadClass(HLoadClass* load_class) override {
+    if (load_class->CanThrow()) {
+      HandleThrowingInstruction(load_class);
+    }
+  }
+
+  void VisitLoadString(HLoadString* load_string) override {
+    if (load_string->CanThrow()) {
+      HandleThrowingInstruction(load_string);
+    }
+  }
+
+  void VisitStringBuilderAppend(HStringBuilderAppend* sb_append) override {
+    HandleThrowingInstruction(sb_append);
+  }
+
   void VisitThrow(HThrow* throw_instruction) override {
-    HandleExit(throw_instruction->GetBlock());
+    HandleThrowingInstruction(throw_instruction);
+  }
+
+  void VisitCheckCast(HCheckCast* check_cast) override {
+    HandleThrowingInstruction(check_cast);
+  }
+
+  void VisitMonitorOperation(HMonitorOperation* monitor_op) override {
+    if (monitor_op->CanThrow()) {
+      HandleThrowingInstruction(monitor_op);
+    }
   }
 
   void HandleInvoke(HInstruction* instruction) {
+    // If `instruction` can throw we have to presume all stores are visible.
+    const bool can_throw = instruction->CanThrow();
     SideEffects side_effects = instruction->GetSideEffects();
     ScopedArenaVector<ValueRecord>& heap_values =
         heap_values_for_[instruction->GetBlock()->GetBlockId()];
@@ -1124,7 +1183,7 @@
           (ref_info->IsPartialSingleton() && partial_singleton_did_not_escape(ref_info, blk))) {
         // Singleton references cannot be seen by the callee.
       } else {
-        if (side_effects.DoesAnyRead() || side_effects.DoesAnyWrite()) {
+        if (can_throw || side_effects.DoesAnyRead() || side_effects.DoesAnyWrite()) {
           // Previous stores may become visible (read) and/or impossible for LSE to track (write).
           KeepStores(heap_values[i].stored_by);
           heap_values[i].stored_by = Value::PureUnknown();
@@ -1177,11 +1236,11 @@
       // new_instance can potentially be eliminated.
       singleton_new_instances_.push_back(new_instance);
     }
-    ScopedArenaVector<ValueRecord>& heap_values =
-        heap_values_for_[new_instance->GetBlock()->GetBlockId()];
+    HBasicBlock* block = new_instance->GetBlock();
+    ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[block->GetBlockId()];
     for (size_t i = 0u, size = heap_values.size(); i != size; ++i) {
-      HInstruction* ref =
-          heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo()->GetReference();
+      ReferenceInfo* info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo();
+      HInstruction* ref = info->GetReference();
       size_t offset = heap_location_collector_.GetHeapLocation(i)->GetOffset();
       if (ref == new_instance) {
         if (offset >= mirror::kObjectHeaderSize ||
@@ -1195,6 +1254,10 @@
           heap_values[i].value = Value::ForInstruction(new_instance->GetLoadClass());
           heap_values[i].stored_by = Value::PureUnknown();
         }
+      } else if (IsEscapingObject(info, block, i)) {
+        // Since NewInstance can throw, we presume all previous stores could be visible.
+        KeepStores(heap_values[i].stored_by);
+        heap_values[i].stored_by = Value::PureUnknown();
       }
     }
   }
@@ -1214,19 +1277,29 @@
         // new_array may throw NegativeArraySizeException. Keep it.
       }
     }
-    ScopedArenaVector<ValueRecord>& heap_values =
-        heap_values_for_[new_array->GetBlock()->GetBlockId()];
+    HBasicBlock* block = new_array->GetBlock();
+    ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[block->GetBlockId()];
     for (size_t i = 0u, size = heap_values.size(); i != size; ++i) {
       HeapLocation* location = heap_location_collector_.GetHeapLocation(i);
-      HInstruction* ref = location->GetReferenceInfo()->GetReference();
+      ReferenceInfo* info = location->GetReferenceInfo();
+      HInstruction* ref = info->GetReference();
       if (ref == new_array && location->GetIndex() != nullptr) {
         // Array elements are set to default heap values.
         heap_values[i].value = Value::Default();
         heap_values[i].stored_by = Value::PureUnknown();
+      } else if (IsEscapingObject(info, block, i)) {
+        // Since NewArray can throw, we presume all previous stores could be visible.
+        KeepStores(heap_values[i].stored_by);
+        heap_values[i].stored_by = Value::PureUnknown();
       }
     }
   }
 
+  void VisitInstruction(HInstruction* instruction) override {
+    // Throwing instructions must be handled specially.
+    DCHECK(!instruction->CanThrow());
+  }
+
   bool ShouldPerformPartialLSE() const {
     return perform_partial_lse_ && !GetGraph()->IsCompilingOsr();
   }
@@ -1829,7 +1902,7 @@
 
   if (instruction->CanThrow()) {
     // Previous stores can become visible.
-    HandleExit(instruction->GetBlock());
+    HandleThrowingInstruction(instruction);
     // We cannot remove a possibly throwing store.
     // After marking it as kept, it does not matter if we track it in `stored_by` or not.
     kept_stores_.SetBit(instruction->GetId());
diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java
index e97bd36..5d55d3e 100644
--- a/test/530-checker-lse/src/Main.java
+++ b/test/530-checker-lse/src/Main.java
@@ -1021,13 +1021,18 @@
 
   /// CHECK-START: int Main.test33(TestClass, boolean) load_store_elimination (after)
   /// CHECK-DAG:                     InstanceFieldSet
-  /// CHECK-DAG:                     Phi
+  /// CHECK-DAG:                     InstanceFieldSet
+  /// CHECK-DAG: <<Phi:i\d+>>        Phi
 
   /// CHECK-START: int Main.test33(TestClass, boolean) load_store_elimination (after)
   /// CHECK:                         InstanceFieldSet
+  /// CHECK:                         InstanceFieldSet
   /// CHECK-NOT:                     InstanceFieldSet
 
-  // Test eliminating non-observable stores.
+  // Test that we are not eliminating the if/else sets to `obj.i`. We have `NullCheck`s on `obj`
+  // when doing `obj.i`. Since `NullCheck` can throw, we save the stores.
+  // The 3rd `obj.i` set is redundant and can be eliminated. It will have the same value and it is
+  // not needed.
   static int test33(TestClass obj, boolean x) {
     int phi;
     if (x) {
@@ -1217,6 +1222,48 @@
     return obj.next.i;
   }
 
+  private static int test40() {
+    int[] array = new int[1];
+    try {
+      $noinline$fillArrayTest40(array, 100, 0);
+      System.out.println("UNREACHABLE");
+    } catch (Throwable expected) {
+    }
+    assertIntEquals(array[0], 1);
+    try {
+      $noinline$fillArrayTest40(array, 100, 1);
+      System.out.println("UNREACHABLE");
+    } catch (Throwable expected) {
+    }
+    assertIntEquals(array[0], 2);
+    $noinline$fillArrayTest40(array, 100, 2);
+    assertIntEquals(array[0], 150);
+    return array[0];
+  }
+
+  /// CHECK-START: void Main.$noinline$fillArrayTest40(int[], int, int) load_store_elimination (before)
+  /// CHECK:                     ArraySet
+  /// CHECK:                     DivZeroCheck
+  /// CHECK:                     ArraySet
+  /// CHECK:                     DivZeroCheck
+  /// CHECK:                     ArraySet
+
+  /// CHECK-START: void Main.$noinline$fillArrayTest40(int[], int, int) load_store_elimination (after)
+  /// CHECK:                     ArraySet
+  /// CHECK:                     DivZeroCheck
+  /// CHECK:                     ArraySet
+  /// CHECK:                     DivZeroCheck
+  /// CHECK:                     ArraySet
+
+  // Check that the stores to array[0] are not eliminated since we can throw in between the stores.
+  private static void $noinline$fillArrayTest40(int[] array, int a, int b) {
+    array[0] = 1;
+    int x = a / b;
+    array[0] = 2;
+    int y = a / (b - 1);
+    array[0] = x + y;
+  }
+
   /// CHECK-START: int Main.$noinline$testConversion1(TestClass, int) load_store_elimination (before)
   /// CHECK-DAG:                     InstanceFieldSet
   /// CHECK-DAG:                     InstanceFieldSet
@@ -1655,12 +1702,13 @@
   /// CHECK: InstanceFieldSet
 
   /// CHECK-START: int Main.testStoreStore6(TestClass2, TestClass2) load_store_elimination (after)
-  /// CHECK-NOT: InstanceFieldSet
+  /// CHECK: InstanceFieldSet
   /// CHECK: InstanceFieldGet
   /// CHECK: InstanceFieldSet
 
   private static int testStoreStore6(TestClass2 obj1, TestClass2 obj2) {
-    obj1.i = 81;      // This store is not needed since obj2.j cannot load from it.
+    obj1.i = 81; // Even though the value in `obj1.i` will be overridden below, this store is needed
+                 // since obj2.j has a NullCheck and can throw.
     int j = obj2.j;
     obj1.i = 82;
     return j;
@@ -4116,6 +4164,7 @@
     assertIntEquals(test38(new TestClass(), false), 2);
     assertIntEquals(test39(new TestClass(), true), 0);
     assertIntEquals(test39(new TestClass(), false), 1);
+    assertIntEquals(test40(), 150);
 
     testFinalizableByForcingGc();
     testFinalizableWithLoopByForcingGc();
diff --git a/test/530-checker-lse2/Android.bp b/test/530-checker-lse2/Android.bp
deleted file mode 100644
index ca5e7f0..0000000
--- a/test/530-checker-lse2/Android.bp
+++ /dev/null
@@ -1,43 +0,0 @@
-// Generated by `regen-test-files`. Do not edit manually.
-
-// Build rules for ART run-test `530-checker-lse2`.
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "art_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["art_license"],
-}
-
-// Test's Dex code.
-java_test {
-    name: "art-run-test-530-checker-lse2",
-    defaults: ["art-run-test-defaults"],
-    test_config_template: ":art-run-test-target-template",
-    srcs: ["src/**/*.java"],
-    data: [
-        ":art-run-test-530-checker-lse2-expected-stdout",
-        ":art-run-test-530-checker-lse2-expected-stderr",
-    ],
-    // Include the Java source files in the test's artifacts, to make Checker assertions
-    // available to the TradeFed test runner.
-    include_srcs: true,
-}
-
-// Test's expected standard output.
-genrule {
-    name: "art-run-test-530-checker-lse2-expected-stdout",
-    out: ["art-run-test-530-checker-lse2-expected-stdout.txt"],
-    srcs: ["expected-stdout.txt"],
-    cmd: "cp -f $(in) $(out)",
-}
-
-// Test's expected standard error.
-genrule {
-    name: "art-run-test-530-checker-lse2-expected-stderr",
-    out: ["art-run-test-530-checker-lse2-expected-stderr.txt"],
-    srcs: ["expected-stderr.txt"],
-    cmd: "cp -f $(in) $(out)",
-}
diff --git a/test/530-checker-lse2/expected-stderr.txt b/test/530-checker-lse2/expected-stderr.txt
deleted file mode 100644
index e69de29..0000000
--- a/test/530-checker-lse2/expected-stderr.txt
+++ /dev/null
diff --git a/test/530-checker-lse2/expected-stdout.txt b/test/530-checker-lse2/expected-stdout.txt
deleted file mode 100644
index e18fc7e..0000000
--- a/test/530-checker-lse2/expected-stdout.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-Start....
-r  = 9.649776E8
-mZ = false
-mI = 0
-mJ = -576460752303423488
-mF = NaN
-mD = NaN
-Done....
diff --git a/test/530-checker-lse2/info.txt b/test/530-checker-lse2/info.txt
deleted file mode 100644
index 8dd3f50..0000000
--- a/test/530-checker-lse2/info.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Checker test for testing store/allocation elimination in presence of
-HDeoptimize.
diff --git a/test/530-checker-lse2/src/Main.java b/test/530-checker-lse2/src/Main.java
deleted file mode 100644
index 491a9a1..0000000
--- a/test/530-checker-lse2/src/Main.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2016 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.util.Arrays;
-
-// Modified from a fuzz test.
-public class Main {
-
-  private interface X {
-    int x();
-  }
-
-  private class A {
-    public int a() {
-      return (+ (Math.multiplyExact(mI, mI)));
-    }
-  }
-
-  private class B extends A implements X {
-    public int a() {
-      return super.a() + ((int) (Math.max(364746077.0f, ((float) mD))));
-    }
-    public int x() {
-      return (mI >> (mI++));
-    }
-  }
-
-  private static class C implements X {
-    public static int s() {
-      return 671468641;
-    }
-    public int c() {
-      return -383762838;
-    }
-    public int x() {
-      return -138813312;
-    }
-  }
-
-  private A mA  = new B();
-  private B mB  = new B();
-  private X mBX = new B();
-  private C mC  = new C();
-  private X mCX = new C();
-
-  private boolean mZ = false;
-  private int     mI = 0;
-  private long    mJ = 0;
-  private float   mF = 0;
-  private double  mD = 0;
-
-  private boolean[] mArray = new boolean[576];
-
-  private Main() {
-    boolean a = false;
-    for (int i0 = 0; i0 < 576; i0++) {
-      mArray[i0] = a;
-      a = !a;
-    }
-  }
-
-  /// CHECK-START: float Main.testMethod() load_store_elimination (before)
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: NewInstance
-  /// CHECK-DAG: ConstructorFence
-  /// CHECK-DAG: NewInstance
-  /// CHECK-DAG: ConstructorFence
-  /// CHECK-DAG: NewInstance
-  /// CHECK-DAG: ConstructorFence
-  /// CHECK-DAG: NewInstance
-  /// CHECK-DAG: ConstructorFence
-  /// CHECK-DAG: NewInstance
-  /// CHECK-DAG: ConstructorFence
-  /// CHECK-DAG: NewInstance
-  /// CHECK-DAG: ConstructorFence
-  /// CHECK-DAG: NewInstance
-  /// CHECK-DAG: ConstructorFence
-  /// CHECK-DAG: NewInstance
-  /// CHECK-DAG: ConstructorFence
-  /// CHECK-DAG: NewInstance
-  /// CHECK-DAG: ConstructorFence
-  /// CHECK-DAG: NewInstance
-  /// CHECK-DAG: ConstructorFence
-  /// CHECK-DAG: NewInstance
-  /// CHECK-DAG: ConstructorFence
-  /// CHECK-DAG: NewInstance
-  /// CHECK-DAG: NewInstance
-  /// CHECK-DAG: NewInstance
-  /// CHECK-NOT: NewInstance
-
-  /// CHECK-START: float Main.testMethod() load_store_elimination (after)
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-NOT: NewInstance
-  /// CHECK-NOT: ConstructorFence
-
-  private float testMethod() {
-    {
-      // Each of the "new" statements here will initialize an object with final fields,
-      // which after inlining will also retain a constructor fence.
-      //
-      // After LSE we remove the 'new-instance' and the associated constructor fence.
-      int lI0 = (-1456058746 << mI);
-      mD = ((double)(int)(double) mD);
-      for (int i0 = 56 - 1; i0 >= 0; i0--) {
-        mArray[i0] &= (Boolean.logicalOr(((true ? ((boolean) new Boolean((mZ))) : mZ) || mArray[i0]), (mZ)));
-        mF *= (mF * mF);
-        if ((mZ ^ true)) {
-          mF *= ((float)(int)(float) 267827331.0f);
-          mZ ^= ((false & ((boolean) new Boolean(false))) | mZ);
-          for (int i1 = 576 - 1; i1 >= 0; i1--) {
-            mZ &= ((mArray[279]) | ((boolean) new Boolean(true)));
-            mD -= (--mD);
-            for (int i2 = 56 - 1; i2 >= 0; i2--) {
-              mF /= (mF - mF);
-              mI = (Math.min(((int) new Integer(mI)), (766538816 * (++mI))));
-              mF += (mZ ? (mB.a()) : ((! mZ) ? -752042357.0f : (++mF)));
-              mJ |= ((long) new Long((-2084191070L + (mJ | mJ))));
-              lI0 |= ((int) new Integer(((int) new Integer(mI))));
-              if (((boolean) new Boolean(false))) {
-                mZ &= (mZ);
-                mF *= (mF--);
-                mD = (Double.POSITIVE_INFINITY);
-                mF += ((float)(int)(float) (-2026938813.0f * 638401585.0f));
-                mJ = (--mJ);
-                for (int i3 = 56 - 1; i3 >= 0; i3--) {
-                  mI &= (- mI);
-                  mD = (--mD);
-                  mArray[426] = (mZ || false);
-                  mF -= (((this instanceof Main) ? mF : mF) + 976981405.0f);
-                  mZ &= ((mZ) & (this instanceof Main));
-                }
-                mZ ^= (Float.isFinite(-1975953895.0f));
-              } else {
-                mJ /= ((long) (Math.nextDown(-1519600008.0f)));
-                mJ <<= (Math.round(1237681786.0));
-              }
-            }
-            mArray[i0] &= (false || ((1256071300.0f != -353296391.0f) ? false : (mZ ^ mArray[i0])));
-            mF *= (+ ((float) mD));
-            for (int i2 = 0; i2 < 576; i2++) {
-              mD *= ((double) lI0);
-              lI0 = (lI0 & (Integer.MIN_VALUE));
-              mF -= (--mF);
-            }
-            if ((this instanceof Main)) {
-              mZ ^= ((boolean) new Boolean(true));
-            } else {
-              {
-                int lI1 = (mZ ? (--lI0) : 1099574344);
-                mJ >>= (Math.incrementExact(mJ));
-                mJ = (~ -2103354070L);
-              }
-            }
-          }
-        } else {
-          mJ *= (- ((long) new Long(479832084L)));
-          mJ %= (Long.MAX_VALUE);
-          mD /= (--mD);
-          if ((mI > ((mBX.x()) << mI))) {
-            {
-              long lJ0 = (mJ--);
-              mI >>>= (mBX.x());
-            }
-            mF = (+ 505094603.0f);
-            mD *= (((boolean) new Boolean((! false))) ? mD : 1808773781.0);
-            mI *= (Integer.MIN_VALUE);
-            for (int i1 = 576 - 1; i1 >= 0; i1--) {
-              if (((boolean) new Boolean(false))) {
-                mD += ((double)(float)(double) -1051436901.0);
-              } else {
-                mF -= ((float)(int)(float) (Float.min(mF, (mF--))));
-              }
-              for (int i2 = 0; i2 < 576; i2++) {
-                mJ -= ((long) new Long(-1968644857L));
-                mJ ^= (+ (mC.s()));
-              }
-            }
-          } else {
-            mF -= ((- mF) + -2145489966.0f);
-          }
-          mD -= (mD++);
-          mD = (949112777.0 * 1209996119.0);
-        }
-        mZ &= (Boolean.logicalAnd(true, ((mZ) & (((boolean) new Boolean(true)) && true))));
-      }
-    }
-    return ((float) 964977619L);
-  }
-
-  public static void main(String[] args) {
-    System.out.println("Start....");
-    Main t = new Main();
-    float r = 1883600237.0f;
-    try {
-      r = t.testMethod();
-    } catch (Exception e) {
-      // Arithmetic, null pointer, index out of bounds, etc.
-      System.out.println("An exception was caught.");
-    }
-    System.out.println("r  = " + r);
-    System.out.println("mZ = " + t.mZ);
-    System.out.println("mI = " + t.mI);
-    System.out.println("mJ = " + t.mJ);
-    System.out.println("mF = " + t.mF);
-    System.out.println("mD = " + t.mD);
-    System.out.println("Done....");
-  }
-}
-
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 9a1bdad..75dc8fe 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -222,8 +222,7 @@
         option="$1"
         FLAGS="${FLAGS} $option"
         if [ "x$option" = "x-Xmethod-trace" ]; then
-            # Method tracing can slow some tests down a lot, in particular
-            # 530-checker-lse2.
+            # Method tracing can slow some tests down a lot.
             TIME_OUT_EXTRA=$((${TIME_OUT_EXTRA} + 1200))
         fi
         shift
diff --git a/test/knownfailures.json b/test/knownfailures.json
index c258f0f..3e485f6 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -375,7 +375,6 @@
     },
     {
         "tests": ["530-checker-lse",
-                  "530-checker-lse2",
                   "030-bad-finalizer",
                   "080-oom-throw",
                   "1336-short-finalizer-timeout",
@@ -1259,7 +1258,7 @@
         "description" : ["Gcstress requires the ability to open at least one file which means this test fails when it runs out."]
     },
     {
-        "tests": ["530-checker-lse2", "141-class-unload", "071-dexfile"],
+        "tests": ["141-class-unload", "071-dexfile"],
         "variant": "gcstress",
         "bug": "b/111543628",
         "description" : ["Test seems to timeout when run with gcstress due to slower unwinding by libbacktrace"]