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);