Allow inlining invokes that contain try catches into catch blocks

Since catch blocks are never considered try blocks, we can
guarantee that its invokes are not inside a TryBoundary (which
is the blocker for enabling inlining of try catch invokes inside
try blocks).

Bug: 227283224
Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b
Change-Id: I747e2e8c2515e36041ad3966ca6a6388ef7d91df
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index e8b9b58..3e3b2d4 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1440,17 +1440,17 @@
           << " is not inlined because inlining try catches is disabled globally";
       return false;
     }
-    const bool inlined_into_try_catch =
-        // Direct parent is a try catch.
-        invoke_instruction->GetBlock()->GetTryCatchInformation() != nullptr ||
-        // Indirect parent is a try catch.
+    const bool disallowed_try_catch_inlining =
+        // Direct parent is a try block.
+        invoke_instruction->GetBlock()->IsTryBlock() ||
+        // Indirect parent disallows try catch inlining.
         !try_catch_inlining_allowed_;
-    if (inlined_into_try_catch) {
+    if (disallowed_try_catch_inlining) {
       LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedTryCatchCallee)
           << "Method " << method->PrettyMethod()
           << " is not inlined because it has a try catch and we are not supporting it for this"
           << " particular call. This is could be because e.g. it would be inlined inside another"
-          << " try catch, we arrived here from TryInlinePolymorphicCall, etc.";
+          << " try block, we arrived here from TryInlinePolymorphicCall, etc.";
       return false;
     }
   }
@@ -2139,8 +2139,8 @@
   const bool try_catch_inlining_allowed_for_recursive_inline =
       // It was allowed previously.
       try_catch_inlining_allowed_ &&
-      // The current invoke is not in a try or a catch.
-      invoke_instruction->GetBlock()->GetTryCatchInformation() == nullptr;
+      // The current invoke is not a try block.
+      !invoke_instruction->GetBlock()->IsTryBlock();
   RunOptimizations(callee_graph,
                    code_item,
                    dex_compilation_unit,
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 4a0ec93..270bb4f 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2740,8 +2740,8 @@
     }
   }
 
-  DCHECK_IMPLIES(has_more_specific_try_catch_info, reference->GetTryCatchInformation() == nullptr)
-      << "We don't allow to inline try catches inside of other try catches.";
+  DCHECK_IMPLIES(has_more_specific_try_catch_info, !reference->IsTryBlock())
+      << "We don't allow to inline try catches inside of other try blocks.";
 
   // Update the TryCatchInformation, if we are not inlining a try catch.
   if (!has_more_specific_try_catch_info) {
@@ -2832,6 +2832,7 @@
 
     HBasicBlock* first = entry_block_->GetSuccessors()[0];
     DCHECK(!first->IsInLoop());
+    DCHECK(first->GetTryCatchInformation() == nullptr);
     at->MergeWithInlined(first);
     exit_block_->ReplaceWith(to);
 
diff --git a/test/2241-checker-inline-try-catch/src/Main.java b/test/2241-checker-inline-try-catch/src/Main.java
index a76a99b..a80fbd7 100644
--- a/test/2241-checker-inline-try-catch/src/Main.java
+++ b/test/2241-checker-inline-try-catch/src/Main.java
@@ -23,7 +23,8 @@
     $noinline$testTryCatchFinally();
     $noinline$testTryCatchFinallyDifferentInputs();
     $noinline$testRecursiveTryCatch();
-    $noinline$testDoNotInlineInsideTryOrCatch();
+    $noinline$testDoNotInlineInsideTryInlineInsideCatch();
+    $noinline$testInlineInsideNestedCatches();
     $noinline$testBeforeAfterTryCatch();
     $noinline$testDifferentTypes();
     $noinline$testRawThrow();
@@ -88,28 +89,46 @@
     $noinline$assertEquals(1, $inline$OOBTryCatchLevel4(numbers));
   }
 
-  // Tests that we don't inline inside outer tries or catches.
-  /// CHECK-START: void Main.$noinline$testDoNotInlineInsideTryOrCatch() inliner (before)
+  // Tests that we don't inline inside outer tries, but we do inline inside of catches.
+  /// CHECK-START: void Main.$noinline$testDoNotInlineInsideTryInlineInsideCatch() inliner (before)
   /// CHECK:       InvokeStaticOrDirect method_name:Main.DoNotInlineOOBTryCatch
-  /// CHECK:       InvokeStaticOrDirect method_name:Main.DoNotInlineOOBTryCatch
+  /// CHECK:       InvokeStaticOrDirect method_name:Main.$inline$OOBTryCatch
 
-  /// CHECK-START: void Main.$noinline$testDoNotInlineInsideTryOrCatch() inliner (after)
+  /// CHECK-START: void Main.$noinline$testDoNotInlineInsideTryInlineInsideCatch() inliner (after)
   /// CHECK:       InvokeStaticOrDirect method_name:Main.DoNotInlineOOBTryCatch
-  /// CHECK:       InvokeStaticOrDirect method_name:Main.DoNotInlineOOBTryCatch
-  private static void $noinline$testDoNotInlineInsideTryOrCatch() {
+  private static void $noinline$testDoNotInlineInsideTryInlineInsideCatch() {
     int val = 0;
     try {
       int[] numbers = {};
       val = DoNotInlineOOBTryCatch(numbers);
     } catch (Exception ex) {
       unreachable();
-      // This is unreachable but we will still compile it so it works for checker purposes
+      // This is unreachable but we will still compile it so it works for checking that it inlines.
       int[] numbers = {};
-      DoNotInlineOOBTryCatch(numbers);
+      $inline$OOBTryCatch(numbers);
     }
     $noinline$assertEquals(1, val);
   }
 
+  private static void $noinline$emptyMethod() {}
+
+  private static void $inline$testInlineInsideNestedCatches_inner() {
+    try {
+      $noinline$emptyMethod();
+    } catch (Exception ex) {
+      int[] numbers = {};
+      $noinline$assertEquals(1, $inline$OOBTryCatch(numbers));
+    }
+  }
+
+  private static void $noinline$testInlineInsideNestedCatches() {
+    try {
+      $noinline$emptyMethod();
+    } catch (Exception ex) {
+      $inline$testInlineInsideNestedCatches_inner();
+    }
+  }
+
   // Tests that outer tries or catches don't affect as long as we are not inlining the inner
   // try/catch inside of them.
   private static void $noinline$testBeforeAfterTryCatch() {