diff options
-rw-r--r-- | compiler/optimizing/load_store_elimination.cc | 48 | ||||
-rw-r--r-- | test/530-checker-lse-try-catch/src/Main.java | 66 |
2 files changed, 92 insertions, 22 deletions
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index d4ceca56ab..cafc3e9c16 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -1020,9 +1020,25 @@ class LSEVisitor final : private HGraphDelegateVisitor { VisitSetLocation(instruction, idx, instruction->GetValue()); } + static bool IsBlockInsideATry(HBasicBlock* block) { + TryCatchInformation* try_catch_info = block->GetTryCatchInformation(); + if (try_catch_info == nullptr) { + return false; + } + + if (try_catch_info->IsTryBlock()) { + return true; + } + + DCHECK(try_catch_info->IsCatchBlock()); + + // The catch block has an xhandler iff it is inside of an outer try. + return block->GetExceptionalSuccessors().size() != 0; + } + void VisitDeoptimize(HDeoptimize* instruction) override { - // If we are in a try catch, even singletons are observable. - const bool in_try_catch = instruction->GetBlock()->GetTryCatchInformation() != nullptr; + // If we are in a try, even singletons are observable. + const bool inside_a_try = IsBlockInsideATry(instruction->GetBlock()); 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) { @@ -1034,7 +1050,7 @@ class LSEVisitor final : private HGraphDelegateVisitor { // for singletons that don't escape in the deoptimization environment. bool observable = true; ReferenceInfo* info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo(); - if (!in_try_catch && info->IsSingleton()) { + if (!inside_a_try && info->IsSingleton()) { HInstruction* reference = info->GetReference(); // Finalizable objects always escape. const bool finalizable_object = @@ -1080,10 +1096,8 @@ class LSEVisitor final : private HGraphDelegateVisitor { void HandleThrowingInstruction(HInstruction* instruction) { DCHECK(instruction->CanThrow()); - // If we are inside of a try catch, singletons can become visible since we may not exit the - // method. - HandleExit(instruction->GetBlock(), - instruction->GetBlock()->GetTryCatchInformation() != nullptr); + // If we are inside of a try, singletons can become visible since we may not exit the method. + HandleExit(instruction->GetBlock(), IsBlockInsideATry(instruction->GetBlock())); } void VisitMethodEntryHook(HMethodEntryHook* method_entry) override { @@ -1147,9 +1161,9 @@ class LSEVisitor final : private HGraphDelegateVisitor { void HandleInvoke(HInstruction* instruction) { // If `instruction` can throw we have to presume all stores are visible. const bool can_throw = instruction->CanThrow(); - // If we are in a try catch, even singletons are observable. - const bool can_throw_in_try_catch = - can_throw && instruction->GetBlock()->GetTryCatchInformation() != nullptr; + // If we are in a try, even singletons are observable. + const bool can_throw_inside_a_try = + can_throw && IsBlockInsideATry(instruction->GetBlock()); SideEffects side_effects = instruction->GetSideEffects(); ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[instruction->GetBlock()->GetBlockId()]; @@ -1175,7 +1189,7 @@ class LSEVisitor final : private HGraphDelegateVisitor { return cohort.PrecedesBlock(blk); }); }; - if (!can_throw_in_try_catch && + if (!can_throw_inside_a_try && (ref_info->IsSingleton() || // partial and we aren't currently escaping and we haven't escaped yet. (ref_info->IsPartialSingleton() && partial_singleton_did_not_escape(ref_info, blk)))) { @@ -1224,8 +1238,8 @@ class LSEVisitor final : private HGraphDelegateVisitor { } void VisitNewInstance(HNewInstance* new_instance) override { - // If we are in a try catch, even singletons are observable. - const bool in_try_catch = new_instance->GetBlock()->GetTryCatchInformation() != nullptr; + // If we are in a try, even singletons are observable. + const bool inside_a_try = IsBlockInsideATry(new_instance->GetBlock()); ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(new_instance); if (ref_info == nullptr) { // new_instance isn't used for field accesses. No need to process it. @@ -1254,7 +1268,7 @@ class LSEVisitor final : private HGraphDelegateVisitor { heap_values[i].value = Value::ForInstruction(new_instance->GetLoadClass()); heap_values[i].stored_by = Value::PureUnknown(); } - } else if (in_try_catch || IsEscapingObject(info, block, i)) { + } else if (inside_a_try || 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(); @@ -1263,8 +1277,8 @@ class LSEVisitor final : private HGraphDelegateVisitor { } void VisitNewArray(HNewArray* new_array) override { - // If we are in a try catch, even singletons are observable. - const bool in_try_catch = new_array->GetBlock()->GetTryCatchInformation() != nullptr; + // If we are in a try, even singletons are observable. + const bool inside_a_try = IsBlockInsideATry(new_array->GetBlock()); ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(new_array); if (ref_info == nullptr) { // new_array isn't used for array accesses. No need to process it. @@ -1289,7 +1303,7 @@ class LSEVisitor final : private HGraphDelegateVisitor { // Array elements are set to default heap values. heap_values[i].value = Value::Default(); heap_values[i].stored_by = Value::PureUnknown(); - } else if (in_try_catch || IsEscapingObject(info, block, i)) { + } else if (inside_a_try || 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(); diff --git a/test/530-checker-lse-try-catch/src/Main.java b/test/530-checker-lse-try-catch/src/Main.java index 56ef8bda20..68c877b874 100644 --- a/test/530-checker-lse-try-catch/src/Main.java +++ b/test/530-checker-lse-try-catch/src/Main.java @@ -30,7 +30,11 @@ public class Main { assertEquals(1, $noinline$testTryCatchBlocking(new Point(), boolean_throw)); assertEquals(1, $noinline$testTryCatchPhi(new Point(), boolean_throw)); assertEquals(2, $noinline$testTryCatchPhiWithTwoCatches(new Point(), new int[0])); - assertEquals(1, $noinline$testKeepStoreInsideTryCatch()); + assertEquals(1, $noinline$testKeepStoreInsideTry()); + assertEquals(10, $noinline$testDontKeepStoreInsideCatch(new int[]{10})); + assertEquals(30, $noinline$testDontKeepStoreInsideCatch(new int[]{})); + assertEquals(10, $noinline$testKeepStoreInsideCatchWithOuterTry(new int[]{10})); + assertEquals(30, $noinline$testKeepStoreInsideCatchWithOuterTry(new int[]{})); assertEquals(150, $noinline$test40()); } @@ -205,17 +209,17 @@ public class Main { // is observable. // Consistency check to make sure the try/catch wasn't removed by an earlier pass. - /// CHECK-START: int Main.$noinline$testKeepStoreInsideTryCatch() load_store_elimination (after) + /// CHECK-START: int Main.$noinline$testKeepStoreInsideTry() load_store_elimination (after) /// CHECK-DAG: TryBoundary kind:entry - /// CHECK-START: int Main.$noinline$testKeepStoreInsideTryCatch() load_store_elimination (before) + /// CHECK-START: int Main.$noinline$testKeepStoreInsideTry() load_store_elimination (before) /// CHECK: InstanceFieldSet field_name:Main.sumForKeepStoreInsideTryCatch /// CHECK: InstanceFieldSet field_name:Main.sumForKeepStoreInsideTryCatch - /// CHECK-START: int Main.$noinline$testKeepStoreInsideTryCatch() load_store_elimination (after) + /// CHECK-START: int Main.$noinline$testKeepStoreInsideTry() load_store_elimination (after) /// CHECK: InstanceFieldSet field_name:Main.sumForKeepStoreInsideTryCatch /// CHECK: InstanceFieldSet field_name:Main.sumForKeepStoreInsideTryCatch - private static int $noinline$testKeepStoreInsideTryCatch() { + private static int $noinline$testKeepStoreInsideTry() { Main main = new Main(); main.sumForKeepStoreInsideTryCatch = 0; try { @@ -228,6 +232,58 @@ public class Main { } } + private static int $noinline$returnValue(int value) { + return value; + } + + /// CHECK-START: int Main.$noinline$testDontKeepStoreInsideCatch(int[]) load_store_elimination (before) + /// CHECK: InstanceFieldSet field_name:Main.sumForKeepStoreInsideTryCatch + /// CHECK: InstanceFieldSet field_name:Main.sumForKeepStoreInsideTryCatch + /// CHECK-NOT: InstanceFieldSet field_name:Main.sumForKeepStoreInsideTryCatch + + /// CHECK-START: int Main.$noinline$testDontKeepStoreInsideCatch(int[]) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldSet field_name:Main.sumForKeepStoreInsideTryCatch + private static int $noinline$testDontKeepStoreInsideCatch(int[] array) { + Main main = new Main(); + int value = 0; + try { + value = array[0]; + } catch (Exception e) { + // These sets can be eliminated even though we have invokes since this catch is not part of an + // outer try. + main.sumForKeepStoreInsideTryCatch += $noinline$returnValue(10); + main.sumForKeepStoreInsideTryCatch += $noinline$returnValue(20); + } + return main.sumForKeepStoreInsideTryCatch + value; + } + + /// CHECK-START: int Main.$noinline$testKeepStoreInsideCatchWithOuterTry(int[]) load_store_elimination (before) + /// CHECK: InstanceFieldSet field_name:Main.sumForKeepStoreInsideTryCatch + /// CHECK: InstanceFieldSet field_name:Main.sumForKeepStoreInsideTryCatch + /// CHECK-NOT: InstanceFieldSet field_name:Main.sumForKeepStoreInsideTryCatch + + /// CHECK-START: int Main.$noinline$testKeepStoreInsideCatchWithOuterTry(int[]) load_store_elimination (after) + /// CHECK: InstanceFieldSet field_name:Main.sumForKeepStoreInsideTryCatch + /// CHECK: InstanceFieldSet field_name:Main.sumForKeepStoreInsideTryCatch + /// CHECK-NOT: InstanceFieldSet field_name:Main.sumForKeepStoreInsideTryCatch + private static int $noinline$testKeepStoreInsideCatchWithOuterTry(int[] array) { + Main main = new Main(); + int value = 0; + try { + try { + value = array[0]; + } catch (Exception e) { + // These sets can't be eliminated since this catch is part of a outer try. + main.sumForKeepStoreInsideTryCatch += $noinline$returnValue(10); + main.sumForKeepStoreInsideTryCatch += $noinline$returnValue(20); + } + } catch (Exception e) { + value = 100000; + } + + return main.sumForKeepStoreInsideTryCatch + value; + } + /// CHECK-START: int Main.$noinline$test40() load_store_elimination (before) /// CHECK: ArraySet /// CHECK: DivZeroCheck |