Track finalizable objects in loops

`PrepareLoopStoredBy` is now aware of the finalizable attribute
and will crate a Phi rather than returning `PureUnknown`

Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b
Change-Id: I203af6f7a9f5b02ede18ee038cabee67c667e5d0
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 4bca2bd..d42e4f7 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -1528,9 +1528,14 @@
   // Use the Phi placeholder for `stored_by` to make sure all incoming stores are kept
   // if the value in the location escapes. This is not applicable to singletons that are
   // defined inside the loop as they shall be dead in the loop header.
-  ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(idx)->GetReferenceInfo();
+  const ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(idx)->GetReferenceInfo();
+  const HInstruction* reference = ref_info->GetReference();
+  // Finalizable objects always escape.
+  const bool is_finalizable =
+      reference->IsNewInstance() && reference->AsNewInstance()->IsFinalizable();
   if (ref_info->IsSingleton() &&
-      block->GetLoopInformation()->Contains(*ref_info->GetReference()->GetBlock())) {
+      block->GetLoopInformation()->Contains(*reference->GetBlock()) &&
+      !is_finalizable) {
     return Value::PureUnknown();
   }
   PhiPlaceholder phi_placeholder = GetPhiPlaceholder(block->GetBlockId(), idx);
diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java
index 9f10afe..e97bd36 100644
--- a/test/530-checker-lse/src/Main.java
+++ b/test/530-checker-lse/src/Main.java
@@ -1426,6 +1426,56 @@
     System.out.println("testFinalizableByForcingGc() failed to force gc.");
   }
 
+  /// CHECK-START: void Main.testFinalizable() load_store_elimination (before)
+  /// CHECK: NewInstance
+  /// CHECK: InstanceFieldSet
+  /// CHECK: InstanceFieldSet
+
+  /// CHECK-START: void Main.testFinalizableWithLoop() load_store_elimination (after)
+  /// CHECK: NewInstance
+  /// CHECK: InstanceFieldSet
+  /// CHECK-NOT: InstanceFieldSet
+
+  // Allocations of finalizable objects cannot be eliminated.
+  static void testFinalizableWithLoop() {
+    for (int i = 0; i < 1000; ++i) {
+      Finalizable finalizable = new Finalizable();
+      finalizable.i = Finalizable.VALUE2;
+      finalizable.i = Finalizable.VALUE1;
+    }
+  }
+
+  static void testFinalizableWithLoopByForcingGc() {
+    testFinalizableWithLoop();
+    java.lang.ref.WeakReference<Object> reference = getWeakReference();
+
+    Runtime runtime = Runtime.getRuntime();
+    for (int i = 0; i < 20; ++i) {
+      runtime.gc();
+      System.runFinalization();
+      try {
+        Thread.sleep(1);
+      } catch (InterruptedException e) {
+        throw new AssertionError(e);
+      }
+
+      // Check to see if the weak reference has been garbage collected.
+      if (reference.get() == null) {
+        // A little bit more sleep time to make sure.
+        try {
+          Thread.sleep(100);
+        } catch (InterruptedException e) {
+          throw new AssertionError(e);
+        }
+        if (!Finalizable.sVisited) {
+          System.out.println("finalize() not called.");
+        }
+        return;
+      }
+    }
+    System.out.println("testFinalizableWithLoopByForcingGc() failed to force gc.");
+  }
+
   /// CHECK-START: int Main.$noinline$testHSelect(boolean) load_store_elimination (before)
   /// CHECK: InstanceFieldSet
   /// CHECK: Select
@@ -4068,6 +4118,7 @@
     assertIntEquals(test39(new TestClass(), false), 1);
 
     testFinalizableByForcingGc();
+    testFinalizableWithLoopByForcingGc();
     assertIntEquals($noinline$testHSelect(true), 0xdead);
     int[] array = {2, 5, 9, -1, -3, 10, 8, 4};
     assertIntEquals(sumWithinRange(array, 1, 5), 11);