Inliner will return true when identifying a method as always throws

The reasoning is that we want to run other phases (e.g. dead code
elimination) if we have extra information (i.e. if we now know that
the method always throws).

If we successfully analyzed a method, we don't encode that in the
return type since we use the return type for control flow with the
meaning of 'we inlined the method'.

Bug: 227316307
Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b
Change-Id: Ic91463b89e7ccf326416f32b9df5c07489bf48d8
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 8b41205..f73c0d3 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -140,7 +140,8 @@
     return false;
   }
 
-  bool didInline = false;
+  bool did_inline = false;
+  bool did_set_always_throws = false;
 
   // Initialize the number of instructions for the method being compiled. Recursive calls
   // to HInliner::Run have already updated the instruction count.
@@ -181,8 +182,8 @@
               call->GetMethodReference().PrettyMethod(/* with_signature= */ false);
           // Tests prevent inlining by having $noinline$ in their method names.
           if (callee_name.find("$noinline$") == std::string::npos) {
-            if (TryInline(call)) {
-              didInline = true;
+            if (TryInline(call, &did_set_always_throws)) {
+              did_inline = true;
             } else if (honor_inline_directives) {
               bool should_have_inlined = (callee_name.find("$inline$") != std::string::npos);
               CHECK(!should_have_inlined) << "Could not inline " << callee_name;
@@ -191,8 +192,8 @@
         } else {
           DCHECK(!honor_inline_directives);
           // Normal case: try to inline.
-          if (TryInline(call)) {
-            didInline = true;
+          if (TryInline(call, &did_set_always_throws)) {
+            did_inline = true;
           }
         }
       }
@@ -200,7 +201,7 @@
     }
   }
 
-  return didInline;
+  return did_inline || did_set_always_throws;
 }
 
 static bool IsMethodOrDeclaringClassFinal(ArtMethod* method)
@@ -435,7 +436,7 @@
   return throw_seen;
 }
 
-bool HInliner::TryInline(HInvoke* invoke_instruction) {
+bool HInliner::TryInline(HInvoke* invoke_instruction, /*inout*/ bool* did_set_always_throws) {
   MaybeRecordStat(stats_, MethodCompilationStat::kTryInline);
 
   // Don't bother to move further if we know the method is unresolved or the invocation is
@@ -490,6 +491,7 @@
       // target.
       if (AlwaysThrows(actual_method)) {
         invoke_to_analyze->SetAlwaysThrows(true);
+        *did_set_always_throws = true;
       }
     }
     return result;
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index e98a66b..a2c2085 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -70,7 +70,9 @@
     kInlineCacheMissingTypes = 5
   };
 
-  bool TryInline(HInvoke* invoke_instruction);
+  // We set `did_set_always_throws` as true if we analyzed `invoke_instruction` and it always
+  // throws.
+  bool TryInline(HInvoke* invoke_instruction, /*inout*/ bool* did_set_always_throws);
 
   // Try to inline `resolved_method` in place of `invoke_instruction`. `do_rtp` is whether
   // reference type propagation can run after the inlining. If the inlining is successful, this
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 18b0cf5..6eb3d01 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -637,7 +637,7 @@
            "dead_code_elimination$initial"),
     // Inlining.
     OptDef(OptimizationPass::kInliner),
-    // Simplification (only if inlining occurred).
+    // Simplification (if inlining occurred, or if we analyzed the invoke as "always throwing").
     OptDef(OptimizationPass::kConstantFolding,
            "constant_folding$after_inlining",
            OptimizationPass::kInliner),