diff options
4 files changed, 621 insertions, 86 deletions
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index 2e5ee84d76..e7b95c8d00 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -861,23 +861,33 @@ class LSEVisitor final : private HGraphDelegateVisitor { } void VisitInstanceFieldGet(HInstanceFieldGet* instruction) override { + HInstruction* object = instruction->InputAt(0); if (instruction->IsVolatile()) { - HandleAcquireLoad(instruction); - return; + ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf( + heap_location_collector_.HuntForOriginalReference(object)); + if (!ref_info->IsSingletonAndRemovable()) { + HandleAcquireLoad(instruction); + return; + } + // Treat it as a normal load if it is a removable singleton. } - HInstruction* object = instruction->InputAt(0); const FieldInfo& field = instruction->GetFieldInfo(); VisitGetLocation(instruction, heap_location_collector_.GetFieldHeapLocation(object, &field)); } void VisitInstanceFieldSet(HInstanceFieldSet* instruction) override { + HInstruction* object = instruction->InputAt(0); if (instruction->IsVolatile()) { - HandleReleaseStore(instruction); - return; + ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf( + heap_location_collector_.HuntForOriginalReference(object)); + if (!ref_info->IsSingletonAndRemovable()) { + HandleReleaseStore(instruction); + return; + } + // Treat it as a normal store if it is a removable singleton. } - HInstruction* object = instruction->InputAt(0); const FieldInfo& field = instruction->GetFieldInfo(); HInstruction* value = instruction->InputAt(1); size_t idx = heap_location_collector_.GetFieldHeapLocation(object, &field); @@ -890,8 +900,8 @@ class LSEVisitor final : private HGraphDelegateVisitor { return; } - HInstruction* cls = instruction->InputAt(0); const FieldInfo& field = instruction->GetFieldInfo(); + HInstruction* cls = instruction->InputAt(0); VisitGetLocation(instruction, heap_location_collector_.GetFieldHeapLocation(cls, &field)); } @@ -901,14 +911,30 @@ class LSEVisitor final : private HGraphDelegateVisitor { return; } - HInstruction* cls = instruction->InputAt(0); const FieldInfo& field = instruction->GetFieldInfo(); + HInstruction* cls = instruction->InputAt(0); HInstruction* value = instruction->InputAt(1); size_t idx = heap_location_collector_.GetFieldHeapLocation(cls, &field); VisitSetLocation(instruction, idx, value); } void VisitMonitorOperation(HMonitorOperation* monitor_op) override { + HInstruction* object = monitor_op->InputAt(0); + ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf( + heap_location_collector_.HuntForOriginalReference(object)); + if (ref_info->IsSingletonAndRemovable()) { + // If the object is a removable singleton, we know that no other threads will have + // access to it, and we can remove the MonitorOperation instruction. + // MONITOR_ENTER throws when encountering a null object. If `object` is a removable + // singleton, it is guaranteed to be non-null so we don't have to worry about the NullCheck. + DCHECK(!object->CanBeNull()); + monitor_op->GetBlock()->RemoveInstruction(monitor_op); + MaybeRecordStat(stats_, MethodCompilationStat::kRemovedMonitorOp); + return; + } + + // We detected a monitor operation that we couldn't remove. See also LSEVisitor::Run(). + monitor_op->GetBlock()->GetGraph()->SetHasMonitorOperations(true); if (monitor_op->IsEnter()) { HandleAcquireLoad(monitor_op); } else { @@ -2439,8 +2465,7 @@ void LSEVisitor::ProcessLoopPhiWithUnknownInput(PhiPlaceholder loop_phi_with_unk if (load_or_store->GetBlock() != block) { break; // End of instructions from the current block. } - bool is_store = load_or_store->GetSideEffects().DoesAnyWrite(); - DCHECK_EQ(is_store, IsStore(load_or_store)); + const bool is_store = IsStore(load_or_store); HInstruction* stored_value = nullptr; if (is_store) { auto it = store_records_.find(load_or_store); @@ -2772,6 +2797,10 @@ void LSEVisitor::FindStoresWritingOldValues() { } void LSEVisitor::Run() { + // 0. Set HasMonitorOperations to false. If we encounter some MonitorOperations that we can't + // remove, we will set it to true in VisitMonitorOperation. + GetGraph()->SetHasMonitorOperations(false); + // 1. Process blocks and instructions in reverse post order. for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) { VisitBasicBlock(block); @@ -2813,14 +2842,22 @@ void LSEVisitor::FinishFullLSE() { load->ReplaceWith(substitute); load->GetBlock()->RemoveInstruction(load); + if ((load->IsInstanceFieldGet() && load->AsInstanceFieldGet()->IsVolatile()) || + (load->IsStaticFieldGet() && load->AsStaticFieldGet()->IsVolatile())) { + MaybeRecordStat(stats_, MethodCompilationStat::kRemovedVolatileLoad); + } } // Remove all the stores we can. for (const LoadStoreRecord& record : loads_and_stores_) { - bool is_store = record.load_or_store->GetSideEffects().DoesAnyWrite(); - DCHECK_EQ(is_store, IsStore(record.load_or_store)); - if (is_store && !kept_stores_.IsBitSet(record.load_or_store->GetId())) { + if (IsStore(record.load_or_store) && !kept_stores_.IsBitSet(record.load_or_store->GetId())) { record.load_or_store->GetBlock()->RemoveInstruction(record.load_or_store); + if ((record.load_or_store->IsInstanceFieldSet() && + record.load_or_store->AsInstanceFieldSet()->IsVolatile()) || + (record.load_or_store->IsStaticFieldSet() && + record.load_or_store->AsStaticFieldSet()->IsVolatile())) { + MaybeRecordStat(stats_, MethodCompilationStat::kRemovedVolatileStore); + } } } diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h index 4549af3cbf..60d18d2f24 100644 --- a/compiler/optimizing/optimizing_compiler_stats.h +++ b/compiler/optimizing/optimizing_compiler_stats.h @@ -50,6 +50,9 @@ enum class MethodCompilationStat { kRemovedDeadPhi, kRemovedTry, kRemovedNullCheck, + kRemovedVolatileLoad, + kRemovedVolatileStore, + kRemovedMonitorOp, kNotCompiledSkipped, kNotCompiledInvalidBytecode, kNotCompiledThrowCatchLoop, diff --git a/test/2242-checker-lse-acquire-release-operations/src/Main.java b/test/2242-checker-lse-acquire-release-operations/src/Main.java index 433a4cd343..4db0f359ef 100644 --- a/test/2242-checker-lse-acquire-release-operations/src/Main.java +++ b/test/2242-checker-lse-acquire-release-operations/src/Main.java @@ -24,63 +24,126 @@ class TestClass { public class Main { public static void main(String[] args) { // Volatile accesses. - assertEquals($noinline$testVolatileAccessesMustBeKept(new TestClass()), 3); + assertEquals(3, $noinline$testVolatileAccessesMustBeKept(new TestClass())); + assertEquals(3, $noinline$testSingletonVolatileAccessesCanBeRemoved()); // Volatile loads - Different fields shouldn't alias. - assertEquals($noinline$testVolatileLoadDifferentFields(new TestClass(), new TestClass()), 3); + assertEquals(3, $noinline$testVolatileLoadDifferentFields(new TestClass(), new TestClass())); assertEquals( - $noinline$testVolatileLoadDifferentFieldsBlocking(new TestClass(), new TestClass()), - 3); + 3, $noinline$testVolatileLoadDifferentFieldsBlocking(new TestClass(), new TestClass())); // Volatile loads - Redundant store. - assertEquals($noinline$testVolatileLoadRedundantStore(new TestClass()), 2); - assertEquals($noinline$testVolatileLoadRedundantStoreBlocking(new TestClass()), 2); - assertEquals($noinline$testVolatileLoadRedundantStoreBlockingOnlyLoad(new TestClass()), 2); + assertEquals(2, $noinline$testVolatileLoadRedundantStore(new TestClass())); + assertEquals(2, $noinline$testVolatileLoadRedundantStoreBlocking(new TestClass())); + assertEquals(2, $noinline$testVolatileLoadRedundantStoreBlockingOnlyLoad(new TestClass())); // Volatile loads - Set and merge values. - assertEquals($noinline$testVolatileLoadSetAndMergeValues(new TestClass(), true), 1); - assertEquals($noinline$testVolatileLoadSetAndMergeValues(new TestClass(), false), 2); - assertEquals($noinline$testVolatileLoadSetAndMergeValuesBlocking(new TestClass(), true), 1); - assertEquals($noinline$testVolatileLoadSetAndMergeValuesBlocking(new TestClass(), false), 2); + assertEquals(1, $noinline$testVolatileLoadSetAndMergeValues(new TestClass(), true)); + assertEquals(2, $noinline$testVolatileLoadSetAndMergeValues(new TestClass(), false)); + assertEquals(1, $noinline$testVolatileLoadSetAndMergeValuesBlocking(new TestClass(), true)); + assertEquals(2, $noinline$testVolatileLoadSetAndMergeValuesBlocking(new TestClass(), false)); - // Volatile stores - Different fields shouldn't alias. - assertEquals($noinline$testVolatileStoreDifferentFields(new TestClass(), new TestClass()), 3); + // Volatile loads - Removal - Different fields shouldn't alias. + assertEquals(3, + $noinline$testVolatileLoadDifferentFieldsRemovedSynchronization( + new TestClass(), new TestClass())); + + // Volatile loads - Removal - Redundant store. assertEquals( - $noinline$testVolatileStoreDifferentFieldsBlocking(new TestClass(), new TestClass()), - 3); + 2, $noinline$testVolatileLoadRedundantStoreRemovedSynchronization(new TestClass())); + + // Volatile loads - Removal - Set and merge values. + assertEquals(1, + $noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization( + new TestClass(), true)); + assertEquals(2, + $noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization( + new TestClass(), false)); + + // Volatile loads - Removal - with inlining + assertEquals(2, $noinline$testVolatileLoadInlineMethodWithSynchronizedScope(new TestClass())); + + // Volatile stores - Different fields shouldn't alias. + assertEquals(3, $noinline$testVolatileStoreDifferentFields(new TestClass(), new TestClass())); + assertEquals(3, + $noinline$testVolatileStoreDifferentFieldsBlocking(new TestClass(), new TestClass())); // Volatile stores - Redundant store. - assertEquals($noinline$testVolatileStoreRedundantStore(new TestClass()), 2); - assertEquals($noinline$testVolatileStoreRedundantStoreBlocking(new TestClass()), 2); - assertEquals($noinline$testVolatileStoreRedundantStoreBlockingOnlyLoad(new TestClass()), 2); + assertEquals(2, $noinline$testVolatileStoreRedundantStore(new TestClass())); + assertEquals(2, $noinline$testVolatileStoreRedundantStoreBlocking(new TestClass())); + assertEquals(2, $noinline$testVolatileStoreRedundantStoreBlockingOnlyLoad(new TestClass())); // Volatile stores - Set and merge values. - assertEquals($noinline$testVolatileStoreSetAndMergeValues(new TestClass(), true), 1); - assertEquals($noinline$testVolatileStoreSetAndMergeValues(new TestClass(), false), 2); - assertEquals($noinline$testVolatileStoreSetAndMergeValuesNotBlocking(new TestClass(), true), 1); - assertEquals($noinline$testVolatileStoreSetAndMergeValuesNotBlocking(new TestClass(), false), 2); + assertEquals(1, $noinline$testVolatileStoreSetAndMergeValues(new TestClass(), true)); + assertEquals(2, $noinline$testVolatileStoreSetAndMergeValues(new TestClass(), false)); + assertEquals(1, $noinline$testVolatileStoreSetAndMergeValuesNotBlocking(new TestClass(), true)); + assertEquals( + 2, $noinline$testVolatileStoreSetAndMergeValuesNotBlocking(new TestClass(), false)); + + // Volatile stores - Removal - Different fields shouldn't alias. + assertEquals(3, + $noinline$testVolatileStoreDifferentFieldsRemovedSynchronization( + new TestClass(), new TestClass())); + + // Volatile stores - Removal - Redundant store. + assertEquals( + 2, $noinline$testVolatileStoreRedundantStoreRemovedSynchronization(new TestClass())); + + // Volatile stores - Removal - Set and merge values. + assertEquals(1, + $noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization( + new TestClass(), true)); + assertEquals(2, + $noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization( + new TestClass(), false)); + + // Volatile stores - Removal - with inlining + assertEquals(2, $noinline$testVolatileStoreInlineMethodWithSynchronizedScope(new TestClass())); // Monitor Operations - Different fields shouldn't alias. + // Make sure the static variable used for synchronization is non-null. + classForSync = new TestClass(); + assertEquals( - $noinline$testMonitorOperationDifferentFields(new TestClass(), new TestClass()), 3); - assertEquals($noinline$testMonitorOperationDifferentFieldsBlocking( - new TestClass(), new TestClass()), - 3); + 3, $noinline$testMonitorOperationDifferentFields(new TestClass(), new TestClass())); + assertEquals(3, + $noinline$testMonitorOperationDifferentFieldsBlocking( + new TestClass(), new TestClass())); // Monitor Operations - Redundant store. - assertEquals($noinline$testMonitorOperationRedundantStore(new TestClass()), 2); - assertEquals($noinline$testMonitorOperationRedundantStoreBlocking(new TestClass()), 2); - assertEquals( - $noinline$testMonitorOperationRedundantStoreBlockingOnlyLoad(new TestClass()), 2); - assertEquals($noinline$testMonitorOperationRedundantStoreBlockingExit(new TestClass()), 2); + assertEquals(2, $noinline$testMonitorOperationRedundantStore(new TestClass())); + assertEquals(2, $noinline$testMonitorOperationRedundantStoreBlocking(new TestClass())); + assertEquals(2, $noinline$testMonitorOperationRedundantStoreBlockingOnlyLoad(new TestClass())); + assertEquals(2, $noinline$testMonitorOperationRedundantStoreBlockingExit(new TestClass())); // Monitor Operations - Set and merge values. - assertEquals($noinline$testMonitorOperationSetAndMergeValues(new TestClass(), true), 1); - assertEquals($noinline$testMonitorOperationSetAndMergeValues(new TestClass(), false), 2); + assertEquals(1, $noinline$testMonitorOperationSetAndMergeValues(new TestClass(), true)); + assertEquals(2, $noinline$testMonitorOperationSetAndMergeValues(new TestClass(), false)); + assertEquals(1, $noinline$testMonitorOperationSetAndMergeValuesBlocking(new TestClass(), true)); + assertEquals( + 2, $noinline$testMonitorOperationSetAndMergeValuesBlocking(new TestClass(), false)); + + // Monitor Operations - Removal - Different fields shouldn't alias. + assertEquals(3, + $noinline$testMonitorOperationDifferentFieldsRemovedSynchronization( + new TestClass(), new TestClass())); + + // Monitor Operations - Removal - Redundant store. assertEquals( - $noinline$testMonitorOperationSetAndMergeValuesBlocking(new TestClass(), true), 1); + 2, $noinline$testMonitorOperationRedundantStoreRemovedSynchronization(new TestClass())); + + // Monitor Operations - Removal - Set and merge values. + assertEquals(1, + $noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization( + new TestClass(), true)); + assertEquals(2, + $noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization( + new TestClass(), false)); + + // Monitor Operations - Removal - with inlining + assertEquals(2, $noinline$testMonitorOperationInlineSynchronizedMethod(new TestClass())); assertEquals( - $noinline$testMonitorOperationSetAndMergeValuesBlocking(new TestClass(), false), 2); + 2, $noinline$testMonitorOperationInlineMethodWithSynchronizedScope(new TestClass())); } public static void assertEquals(int expected, int result) { @@ -114,6 +177,31 @@ public class Main { return result; } + /// CHECK-START: int Main.$noinline$testSingletonVolatileAccessesCanBeRemoved() load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet + /// CHECK: InstanceFieldGet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet + + /// CHECK-START: int Main.$noinline$testSingletonVolatileAccessesCanBeRemoved() load_store_elimination (after) + /// CHECK-NOT: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testSingletonVolatileAccessesCanBeRemoved() load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + static int $noinline$testSingletonVolatileAccessesCanBeRemoved() { + Main m = new Main(); + int result; + m.vi = 3; + // Redundant load can be removed. + result = m.vi; + result = m.vi; + // Redundant store can be removed. + m.vi = 3; + result = m.vi; + return result; + } + /// CHECK-START: int Main.$noinline$testVolatileLoadDifferentFields(TestClass, TestClass) load_store_elimination (before) /// CHECK: InstanceFieldGet field_name:TestClass.vi /// CHECK: InstanceFieldSet @@ -288,6 +376,136 @@ public class Main { return obj.i; } + /// CHECK-START: int Main.$noinline$testVolatileLoadDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet field_name:Main.vi + /// CHECK: InstanceFieldGet + /// CHECK: InstanceFieldGet + + /// CHECK-START: int Main.$noinline$testVolatileLoadDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileLoadDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testVolatileLoadDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + + static int $noinline$testVolatileLoadDifferentFieldsRemovedSynchronization( + TestClass obj1, TestClass obj2) { + Main m = new Main(); + + obj1.i = 1; + obj2.j = 2; + int unused = m.vi; + + return obj1.i + obj2.j; + } + + /// CHECK-START: int Main.$noinline$testVolatileLoadRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet field_name:Main.vi + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet field_name:Main.vi + /// CHECK: InstanceFieldGet + + /// CHECK-START: int Main.$noinline$testVolatileLoadRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileLoadRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK-NOT: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testVolatileLoadRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + + static int $noinline$testVolatileLoadRedundantStoreRemovedSynchronization(TestClass obj) { + Main m = new Main(); + + obj.j = 1; + int unused = m.vi; + obj.j = 2; + unused = m.vi; + + return obj.j; + } + + /// CHECK-START: int Main.$noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (before) + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldGet field_name:Main.vi + /// CHECK-DAG: InstanceFieldGet + /// CHECK-DAG: Return + + /// CHECK-START: int Main.$noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: Return + + /// CHECK-START: int Main.$noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK: Phi + + /// CHECK-START: int Main.$noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + + static int $noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization( + TestClass obj, boolean b) { + Main m = new Main(); + + if (b) { + obj.i = 1; + } else { + obj.i = 2; + } + int unused = m.vi; + return obj.i; + } + + // Can't eliminate the setters, or volatile getters in this method. + + /// CHECK-START: int Main.$inline$SetterWithVolatileLoads(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldGet field_name:Main.vi + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldGet field_name:Main.vi + + /// CHECK-START: int Main.$inline$SetterWithVolatileLoads(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldGet field_name:Main.vi + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldGet field_name:Main.vi + int $inline$SetterWithVolatileLoads(TestClass obj) { + obj.j = 1; + int unused = this.vi; + obj.j = 2; + unused = this.vi; + return obj.j; + } + + // But we can eliminate once inlined. + + /// CHECK-START: int Main.$noinline$testVolatileLoadInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldGet field_name:Main.vi + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldGet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileLoadInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileLoadInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK-NOT: InstanceFieldSet field_name:TestClass.j + static int $noinline$testVolatileLoadInlineMethodWithSynchronizedScope(TestClass obj) { + Main m = new Main(); + return m.$inline$SetterWithVolatileLoads(obj); + } + /// CHECK-START: int Main.$noinline$testVolatileStoreDifferentFields(TestClass, TestClass) load_store_elimination (before) /// CHECK: InstanceFieldSet field_name:TestClass.vi /// CHECK: InstanceFieldSet @@ -462,6 +680,136 @@ public class Main { return obj.i; } + /// CHECK-START: int Main.$noinline$testVolatileStoreDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet field_name:Main.vi + /// CHECK: InstanceFieldGet + /// CHECK: InstanceFieldGet + + /// CHECK-START: int Main.$noinline$testVolatileStoreDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldSet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileStoreDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testVolatileStoreDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + + static int $noinline$testVolatileStoreDifferentFieldsRemovedSynchronization( + TestClass obj1, TestClass obj2) { + Main m = new Main(); + + obj1.i = 1; + obj2.j = 2; + m.vi = 123; + + return obj1.i + obj2.j; + } + + /// CHECK-START: int Main.$noinline$testVolatileStoreRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet + + /// CHECK-START: int Main.$noinline$testVolatileStoreRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldSet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileStoreRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK-NOT: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testVolatileStoreRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + + static int $noinline$testVolatileStoreRedundantStoreRemovedSynchronization(TestClass obj) { + Main m = new Main(); + + obj.j = 1; + m.vi = 123; + obj.j = 2; + m.vi = 123; + + return obj.j; + } + + /// CHECK-START: int Main.$noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (before) + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldGet + /// CHECK-DAG: Return + + /// CHECK-START: int Main.$noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: Return + + /// CHECK-START: int Main.$noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldSet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK: Phi + + /// CHECK-START: int Main.$noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + + static int $noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization( + TestClass obj, boolean b) { + Main m = new Main(); + + if (b) { + obj.i = 1; + } else { + obj.i = 2; + } + m.vi = 123; + return obj.i; + } + + // Can't eliminate the setters in this method. + + /// CHECK-START: int Main.$inline$SetterWithVolatileStores(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldSet field_name:Main.vi + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldSet field_name:Main.vi + + /// CHECK-START: int Main.$inline$SetterWithVolatileStores(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldSet field_name:Main.vi + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldSet field_name:Main.vi + int $inline$SetterWithVolatileStores(TestClass obj) { + obj.j = 1; + this.vi = 123; + obj.j = 2; + this.vi = 123; + return obj.j; + } + + // But we can eliminate once inlined. + + /// CHECK-START: int Main.$noinline$testVolatileStoreInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldSet field_name:Main.vi + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldSet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileStoreInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldSet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileStoreInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK-NOT: InstanceFieldSet field_name:TestClass.j + static int $noinline$testVolatileStoreInlineMethodWithSynchronizedScope(TestClass obj) { + Main m = new Main(); + return m.$inline$SetterWithVolatileStores(obj); + } + /// CHECK-START: int Main.$noinline$testMonitorOperationDifferentFields(TestClass, TestClass) load_store_elimination (before) /// CHECK: InstanceFieldSet /// CHECK: InstanceFieldSet @@ -483,15 +831,11 @@ public class Main { // Unrelated monitor operations shouldn't block LSE. static int $noinline$testMonitorOperationDifferentFields(TestClass obj1, TestClass obj2) { - Main m = new Main(); - synchronized (m) {} - + synchronized (classForSync) {} obj1.i = 1; obj2.j = 2; int result = obj1.i + obj2.j; - - synchronized (m) {} - + synchronized (classForSync) {} return result; } @@ -513,11 +857,9 @@ public class Main { // A synchronized operation blocks loads. static int $noinline$testMonitorOperationDifferentFieldsBlocking(TestClass obj1, TestClass obj2) { - Main m = new Main(); - obj1.i = 1; obj2.j = 2; - synchronized (m) { + synchronized (classForSync) { return obj1.i + obj2.j; } } @@ -539,12 +881,10 @@ public class Main { /// CHECK-NOT: InstanceFieldGet static int $noinline$testMonitorOperationRedundantStore(TestClass obj) { - Main m = new Main(); - synchronized (m) { + synchronized (classForSync) { obj.j = 1; obj.j = 2; } - return obj.j; } @@ -565,13 +905,10 @@ public class Main { /// CHECK-NOT: InstanceFieldGet static int $noinline$testMonitorOperationRedundantStoreBlocking(TestClass obj) { - Main m = new Main(); - // This store must be kept due to the monitor operation. obj.j = 1; - synchronized (m) {} + synchronized (classForSync) {} obj.j = 2; - return obj.j; } @@ -592,13 +929,10 @@ public class Main { /// CHECK: InstanceFieldGet static int $noinline$testMonitorOperationRedundantStoreBlockingOnlyLoad(TestClass obj) { - Main m = new Main(); - // This store can be safely removed. obj.j = 1; obj.j = 2; - synchronized (m) {} - + synchronized (classForSync) {} // This load remains due to the monitor operation. return obj.j; } @@ -622,16 +956,13 @@ public class Main { /// CHECK-NOT: InstanceFieldGet static int $noinline$testMonitorOperationRedundantStoreBlockingExit(TestClass obj) { - Main m = new Main(); - - synchronized (m) { + synchronized (classForSync) { // This store can be removed. obj.j = 0; // This store must be kept due to the monitor exit operation. obj.j = 1; } obj.j = 2; - return obj.j; } @@ -658,13 +989,11 @@ public class Main { /// CHECK-NOT: InstanceFieldGet static int $noinline$testMonitorOperationSetAndMergeValues(TestClass obj, boolean b) { - Main m = new Main(); - if (b) { - synchronized (m) {} + synchronized (classForSync) {} obj.i = 1; } else { - synchronized (m) {} + synchronized (classForSync) {} obj.i = 2; } return obj.i; @@ -690,6 +1019,102 @@ public class Main { /// CHECK: InstanceFieldGet static int $noinline$testMonitorOperationSetAndMergeValuesBlocking(TestClass obj, boolean b) { + if (b) { + obj.i = 1; + } else { + obj.i = 2; + } + synchronized (classForSync) {} + return obj.i; + } + + /// CHECK-START: int Main.$noinline$testMonitorOperationDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet + /// CHECK: InstanceFieldGet + + /// CHECK-START: int Main.$noinline$testMonitorOperationDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (before) + /// CHECK: MonitorOperation kind:enter + /// CHECK: MonitorOperation kind:exit + + /// CHECK-START: int Main.$noinline$testMonitorOperationDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK-NOT: MonitorOperation + + /// CHECK-START: int Main.$noinline$testMonitorOperationDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testMonitorOperationDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + + static int $noinline$testMonitorOperationDifferentFieldsRemovedSynchronization( + TestClass obj1, TestClass obj2) { + Main m = new Main(); + + obj1.i = 1; + obj2.j = 2; + synchronized (m) {} + + return obj1.i + obj2.j; + } + + /// CHECK-START: int Main.$noinline$testMonitorOperationRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet + + /// CHECK-START: int Main.$noinline$testMonitorOperationRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (before) + /// CHECK: MonitorOperation kind:enter + /// CHECK: MonitorOperation kind:exit + /// CHECK: MonitorOperation kind:enter + /// CHECK: MonitorOperation kind:exit + + /// CHECK-START: int Main.$noinline$testMonitorOperationRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK-NOT: MonitorOperation + + /// CHECK-START: int Main.$noinline$testMonitorOperationRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK-NOT: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testMonitorOperationRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + static int $noinline$testMonitorOperationRedundantStoreRemovedSynchronization(TestClass obj) { + Main m = new Main(); + + obj.j = 1; + synchronized (m) {} + obj.j = 2; + synchronized (m) {} + + return obj.j; + } + + /// CHECK-START: int Main.$noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (before) + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldGet + /// CHECK-DAG: Return + + /// CHECK-START: int Main.$noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: Return + + /// CHECK-START: int Main.$noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (before) + /// CHECK-DAG: MonitorOperation kind:enter + /// CHECK-DAG: MonitorOperation kind:exit + + /// CHECK-START: int Main.$noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-NOT: MonitorOperation + + /// CHECK-START: int Main.$noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK: Phi + + /// CHECK-START: int Main.$noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + static int $noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization( + TestClass obj, boolean b) { Main m = new Main(); if (b) { @@ -700,4 +1125,75 @@ public class Main { synchronized (m) {} return obj.i; } + + synchronized int $inline$synchronizedSetter(TestClass obj) { + obj.j = 1; + obj.j = 2; + return obj.j; + } + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineSynchronizedMethod(TestClass) inliner (before) + /// CHECK-NOT: MonitorOperation + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineSynchronizedMethod(TestClass) inliner (after) + /// CHECK: MonitorOperation kind:enter + /// CHECK: MonitorOperation kind:exit + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineSynchronizedMethod(TestClass) load_store_elimination (before) + /// CHECK: MonitorOperation kind:enter + /// CHECK: MonitorOperation kind:exit + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineSynchronizedMethod(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK-NOT: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineSynchronizedMethod(TestClass) load_store_elimination (after) + /// CHECK-NOT: MonitorOperation + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineSynchronizedMethod(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK-NOT: InstanceFieldSet + static int $noinline$testMonitorOperationInlineSynchronizedMethod(TestClass obj) { + Main m = new Main(); + return m.$inline$synchronizedSetter(obj); + } + + int $inline$SetterWithSynchronizedScope(TestClass obj) { + synchronized (this) { + obj.j = 1; + obj.j = 2; + return obj.j; + } + } + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineMethodWithSynchronizedScope(TestClass) inliner (before) + /// CHECK-NOT: MonitorOperation + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineMethodWithSynchronizedScope(TestClass) inliner (after) + /// CHECK: MonitorOperation kind:enter + /// CHECK: MonitorOperation kind:exit + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (before) + /// CHECK: MonitorOperation kind:enter + /// CHECK: MonitorOperation kind:exit + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK-NOT: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (after) + /// CHECK-NOT: MonitorOperation + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK-NOT: InstanceFieldSet + static int $noinline$testMonitorOperationInlineMethodWithSynchronizedScope(TestClass obj) { + Main m = new Main(); + return m.$inline$SetterWithSynchronizedScope(obj); + } + + static TestClass classForSync; + volatile int vi; } diff --git a/test/2247-checker-write-barrier-elimination/src/Main.java b/test/2247-checker-write-barrier-elimination/src/Main.java index 76fb05a2c0..c03ada30b5 100644 --- a/test/2247-checker-write-barrier-elimination/src/Main.java +++ b/test/2247-checker-write-barrier-elimination/src/Main.java @@ -50,8 +50,8 @@ public class Main { // instructions that can throw. $noinline$testInstanceFieldSetsBlocked( new Main(), new Object(), new Object(), new Object()); - $noinline$testStaticFieldSetsBlocked(new Object(), new Object(), new Object()); - $noinline$testArraySetsSameRTIBlocked(); + $noinline$testStaticFieldSetsBlocked(new Main(), new Object(), new Object(), new Object()); + $noinline$testArraySetsSameRTIBlocked(new Main()); } /// CHECK-START: Main Main.$noinline$testInstanceFieldSets(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after) @@ -273,46 +273,45 @@ public class Main { return m; } - /// CHECK-START: void Main.$noinline$testStaticFieldSetsBlocked(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after) + /// CHECK-START: void Main.$noinline$testStaticFieldSetsBlocked(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after) /// CHECK: StaticFieldSet field_name:Main.inner_static field_type:Reference write_barrier_kind:EmitWithNullCheck /// CHECK: InvokeStaticOrDirect method_name:Main.$noinline$emptyMethod /// CHECK: StaticFieldSet field_name:Main.inner_static2 field_type:Reference write_barrier_kind:EmitWithNullCheck /// CHECK: MonitorOperation kind:enter /// CHECK: StaticFieldSet field_name:Main.inner_static3 field_type:Reference write_barrier_kind:EmitWithNullCheck - /// CHECK-START: void Main.$noinline$testStaticFieldSetsBlocked(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after) + /// CHECK-START: void Main.$noinline$testStaticFieldSetsBlocked(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after) /// CHECK: ; card_table /// CHECK: ; card_table /// CHECK: ; card_table /// CHECK-NOT: ; card_table - private static void $noinline$testStaticFieldSetsBlocked(Object o, Object o2, Object o3) { + private static void $noinline$testStaticFieldSetsBlocked( + Main m, Object o, Object o2, Object o3) { inner_static = o; $noinline$emptyMethod(); inner_static2 = o2; - Main m = new Main(); synchronized (m) { inner_static3 = o3; } } - /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTIBlocked() disassembly (after) + /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTIBlocked(Main) disassembly (after) /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck /// CHECK: InvokeStaticOrDirect method_name:Main.$noinline$emptyMethod /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck /// CHECK: MonitorOperation kind:enter /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck - /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTIBlocked() disassembly (after) + /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTIBlocked(Main) disassembly (after) /// CHECK: ; card_table /// CHECK: ; card_table /// CHECK: ; card_table /// CHECK-NOT: ; card_table - private static java.lang.Object[] $noinline$testArraySetsSameRTIBlocked() { + private static java.lang.Object[] $noinline$testArraySetsSameRTIBlocked(Main m) { Object[] arr = new Object[3]; arr[0] = inner_static; $noinline$emptyMethod(); arr[1] = inner_static2; - Main m = new Main(); synchronized (m) { arr[2] = inner_static3; } |