Mark graphs as always throwing alongside methods

This CL removes the need of using an extra boolean
(`did_set_always_throws`) as we already encode the information in
HasAlwaysThrowingInvokes after aosp/2153582.

Also, if we know that a method always throws in the particular
instance that it is called, we can mark it as such. This is an
improvement versus using the dex instructions as methods like:

int foo(int a) {
  if (a == 0) { throw new Error("a is 0!"); }
  return a / a;
}

will be marked as always throws if called as foo(0).

Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b
Change-Id: I5368878d0023775c53028a5cccd4a1111b50f60e
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index d8ace5e..3a2f7f2 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -141,7 +141,11 @@
   }
 
   bool did_inline = false;
-  bool did_set_always_throws = false;
+  // The inliner is the only phase that sets invokes as `always throwing`, and since we only run the
+  // inliner once per graph this value should always be false at the beginning of the inlining
+  // phase. This is important since we use `HasAlwaysThrowingInvokes` to know whether the inliner
+  // phase performed a relevant change in the graph.
+  DCHECK(!graph_->HasAlwaysThrowingInvokes());
 
   // Initialize the number of instructions for the method being compiled. Recursive calls
   // to HInliner::Run have already updated the instruction count.
@@ -182,7 +186,7 @@
               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, &did_set_always_throws)) {
+            if (TryInline(call)) {
               did_inline = true;
             } else if (honor_inline_directives) {
               bool should_have_inlined = (callee_name.find("$inline$") != std::string::npos);
@@ -192,7 +196,7 @@
         } else {
           DCHECK(!honor_inline_directives);
           // Normal case: try to inline.
-          if (TryInline(call, &did_set_always_throws)) {
+          if (TryInline(call)) {
             did_inline = true;
           }
         }
@@ -201,11 +205,9 @@
     }
   }
 
-  if (did_set_always_throws) {
-    graph_->SetHasAlwaysThrowingInvokes(/* value= */ true);
-  }
-
-  return did_inline || did_set_always_throws;
+  // We return true if we either inlined at least one method, or we marked one of our methods as
+  // always throwing.
+  return did_inline || graph_->HasAlwaysThrowingInvokes();
 }
 
 static bool IsMethodOrDeclaringClassFinal(ArtMethod* method)
@@ -440,7 +442,7 @@
   return throw_seen;
 }
 
-bool HInliner::TryInline(HInvoke* invoke_instruction, /*inout*/ bool* did_set_always_throws) {
+bool HInliner::TryInline(HInvoke* invoke_instruction) {
   MaybeRecordStat(stats_, MethodCompilationStat::kTryInline);
 
   // Don't bother to move further if we know the method is unresolved or the invocation is
@@ -491,11 +493,10 @@
       } else {
         invoke_to_analyze = invoke_instruction;
       }
-      // Set always throws property for non-inlined method call with single
-      // target.
+      // Set always throws property for non-inlined method call with single target.
       if (AlwaysThrows(actual_method)) {
-        invoke_to_analyze->SetAlwaysThrows(true);
-        *did_set_always_throws = true;
+        invoke_to_analyze->SetAlwaysThrows(/* always_throws= */ true);
+        graph_->SetHasAlwaysThrowingInvokes(/* value= */ true);
       }
     }
     return result;
@@ -1819,8 +1820,9 @@
 // If this function returns true, it will also set out_number_of_instructions to
 // the number of instructions in the inlined body.
 bool HInliner::CanInlineBody(const HGraph* callee_graph,
-                             const HBasicBlock* target_block,
+                             HInvoke* invoke,
                              size_t* out_number_of_instructions) const {
+  const HBasicBlock* target_block = invoke->GetBlock();
   ArtMethod* const resolved_method = callee_graph->GetArtMethod();
 
   HBasicBlock* exit_block = callee_graph->GetExitBlock();
@@ -1862,6 +1864,11 @@
   }
 
   if (!has_one_return) {
+    // If we know that the method always throws with the particular parameters, set it as such. This
+    // is better than using the dex instructions as we have more information about this particular
+    // call.
+    invoke->SetAlwaysThrows(/* always_throws= */ true);
+    graph_->SetHasAlwaysThrowingInvokes(/* value= */ true);
     LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedAlwaysThrows)
         << "Method " << resolved_method->PrettyMethod()
         << " could not be inlined because it always throws";
@@ -2058,7 +2065,7 @@
   RunOptimizations(callee_graph, code_item, dex_compilation_unit);
 
   size_t number_of_instructions = 0;
-  if (!CanInlineBody(callee_graph, invoke_instruction->GetBlock(), &number_of_instructions)) {
+  if (!CanInlineBody(callee_graph, invoke_instruction, &number_of_instructions)) {
     return false;
   }