diff options
-rw-r--r-- | compiler/optimizing/load_store_elimination.cc | 9 | ||||
-rw-r--r-- | test/530-checker-lse/src/Main.java | 51 |
2 files changed, 58 insertions, 2 deletions
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index 4bca2bd323..d42e4f7523 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -1528,9 +1528,14 @@ LSEVisitor::Value LSEVisitor::PrepareLoopStoredBy(HBasicBlock* block, size_t idx // 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 9f10afe819..e97bd36e1c 100644 --- a/test/530-checker-lse/src/Main.java +++ b/test/530-checker-lse/src/Main.java @@ -1426,6 +1426,56 @@ public class Main { 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 @@ public class Main { 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); |