Refactor the inliner.

In preparation for more polymorphic inlining, refactor the inliner
a bit.

Change-Id: Ie3fd6c1ef205f1089989c67a527e6f57ff3c8b5d
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 68e96fb..a5acab8 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -258,8 +258,9 @@
   }
 
   if (actual_method != nullptr) {
-    return TryInline(invoke_instruction, actual_method);
+    return TryInlineAndReplace(invoke_instruction, actual_method, /* do_rtp */ true);
   }
+
   DCHECK(!invoke_instruction->IsInvokeStaticOrDirect());
 
   // Check if we can use an inline cache.
@@ -344,7 +345,7 @@
   HInstruction* cursor = invoke_instruction->GetPrevious();
   HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
 
-  if (!TryInline(invoke_instruction, resolved_method, /* do_rtp */ false)) {
+  if (!TryInlineAndReplace(invoke_instruction, resolved_method, /* do_rtp */ false)) {
     return false;
   }
 
@@ -431,7 +432,7 @@
   HInstruction* cursor = invoke_instruction->GetPrevious();
   HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
 
-  if (!TryInline(invoke_instruction, actual_method, /* do_rtp */ false)) {
+  if (!TryInlineAndReplace(invoke_instruction, actual_method, /* do_rtp */ false)) {
     return false;
   }
 
@@ -485,14 +486,29 @@
   return true;
 }
 
-bool HInliner::TryInline(HInvoke* invoke_instruction, ArtMethod* method, bool do_rtp) {
+bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction, ArtMethod* method, bool do_rtp) {
+  HInstruction* return_replacement = nullptr;
+  if (!TryBuildAndInline(invoke_instruction, method, &return_replacement)) {
+    return false;
+  }
+  if (return_replacement != nullptr) {
+    invoke_instruction->ReplaceWith(return_replacement);
+  }
+  invoke_instruction->GetBlock()->RemoveInstruction(invoke_instruction);
+  FixUpReturnReferenceType(invoke_instruction, method, return_replacement, do_rtp);
+  return true;
+}
+
+bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction,
+                                 ArtMethod* method,
+                                 HInstruction** return_replacement) {
   const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
 
   // Check whether we're allowed to inline. The outermost compilation unit is the relevant
   // dex file here (though the transitivity of an inline chain would allow checking the calller).
   if (!compiler_driver_->MayInline(method->GetDexFile(),
                                    outer_compilation_unit_.GetDexFile())) {
-    if (TryPatternSubstitution(invoke_instruction, method, do_rtp)) {
+    if (TryPatternSubstitution(invoke_instruction, method, return_replacement)) {
       VLOG(compiler) << "Successfully replaced pattern of invoke " << PrettyMethod(method);
       MaybeRecordStat(kReplacedInvokeWithSimplePattern);
       return true;
@@ -559,7 +575,7 @@
     return false;
   }
 
-  if (!TryBuildAndInline(method, invoke_instruction, same_dex_file, do_rtp)) {
+  if (!TryBuildAndInlineHelper(invoke_instruction, method, same_dex_file, return_replacement)) {
     return false;
   }
 
@@ -586,27 +602,27 @@
 // Try to recognize known simple patterns and replace invoke call with appropriate instructions.
 bool HInliner::TryPatternSubstitution(HInvoke* invoke_instruction,
                                       ArtMethod* resolved_method,
-                                      bool do_rtp) {
+                                      HInstruction** return_replacement) {
   InlineMethod inline_method;
   if (!InlineMethodAnalyser::AnalyseMethodCode(resolved_method, &inline_method)) {
     return false;
   }
 
-  HInstruction* return_replacement = nullptr;
   switch (inline_method.opcode) {
     case kInlineOpNop:
       DCHECK_EQ(invoke_instruction->GetType(), Primitive::kPrimVoid);
+      *return_replacement = nullptr;
       break;
     case kInlineOpReturnArg:
-      return_replacement = GetInvokeInputForArgVRegIndex(invoke_instruction,
-                                                         inline_method.d.return_data.arg);
+      *return_replacement = GetInvokeInputForArgVRegIndex(invoke_instruction,
+                                                          inline_method.d.return_data.arg);
       break;
     case kInlineOpNonWideConst:
       if (resolved_method->GetShorty()[0] == 'L') {
         DCHECK_EQ(inline_method.d.data, 0u);
-        return_replacement = graph_->GetNullConstant();
+        *return_replacement = graph_->GetNullConstant();
       } else {
-        return_replacement = graph_->GetIntConstant(static_cast<int32_t>(inline_method.d.data));
+        *return_replacement = graph_->GetIntConstant(static_cast<int32_t>(inline_method.d.data));
       }
       break;
     case kInlineOpIGet: {
@@ -621,7 +637,7 @@
       DCHECK_EQ(iget->GetFieldOffset().Uint32Value(), data.field_offset);
       DCHECK_EQ(iget->IsVolatile() ? 1u : 0u, data.is_volatile);
       invoke_instruction->GetBlock()->InsertInstructionBefore(iget, invoke_instruction);
-      return_replacement = iget;
+      *return_replacement = iget;
       break;
     }
     case kInlineOpIPut: {
@@ -639,7 +655,7 @@
       invoke_instruction->GetBlock()->InsertInstructionBefore(iput, invoke_instruction);
       if (data.return_arg_plus1 != 0u) {
         size_t return_arg = data.return_arg_plus1 - 1u;
-        return_replacement = GetInvokeInputForArgVRegIndex(invoke_instruction, return_arg);
+        *return_replacement = GetInvokeInputForArgVRegIndex(invoke_instruction, return_arg);
       }
       break;
     }
@@ -694,19 +710,13 @@
         HMemoryBarrier* barrier = new (graph_->GetArena()) HMemoryBarrier(kStoreStore, kNoDexPc);
         invoke_instruction->GetBlock()->InsertInstructionBefore(barrier, invoke_instruction);
       }
+      *return_replacement = nullptr;
       break;
     }
     default:
       LOG(FATAL) << "UNREACHABLE";
       UNREACHABLE();
   }
-
-  if (return_replacement != nullptr) {
-    invoke_instruction->ReplaceWith(return_replacement);
-  }
-  invoke_instruction->GetBlock()->RemoveInstruction(invoke_instruction);
-
-  FixUpReturnReferenceType(resolved_method, invoke_instruction, return_replacement, do_rtp);
   return true;
 }
 
@@ -760,10 +770,10 @@
   return iput;
 }
 
-bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
-                                 HInvoke* invoke_instruction,
-                                 bool same_dex_file,
-                                 bool do_rtp) {
+bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction,
+                                       ArtMethod* resolved_method,
+                                       bool same_dex_file,
+                                       HInstruction** return_replacement) {
   ScopedObjectAccess soa(Thread::Current());
   const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
   const DexFile& callee_dex_file = *resolved_method->GetDexFile();
@@ -1016,16 +1026,12 @@
   }
   number_of_inlined_instructions_ += number_of_instructions;
 
-  HInstruction* return_replacement = callee_graph->InlineInto(graph_, invoke_instruction);
-  if (return_replacement != nullptr) {
-    DCHECK_EQ(graph_, return_replacement->GetBlock()->GetGraph());
-  }
-  FixUpReturnReferenceType(resolved_method, invoke_instruction, return_replacement, do_rtp);
+  *return_replacement = callee_graph->InlineInto(graph_, invoke_instruction);
   return true;
 }
 
-void HInliner::FixUpReturnReferenceType(ArtMethod* resolved_method,
-                                        HInvoke* invoke_instruction,
+void HInliner::FixUpReturnReferenceType(HInvoke* invoke_instruction,
+                                        ArtMethod* resolved_method,
                                         HInstruction* return_replacement,
                                         bool do_rtp) {
   // Check the integrity of reference types and run another type propagation if needed.
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index 7d343c6..9dd9bf5 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -61,12 +61,25 @@
   bool TryInline(HInvoke* invoke_instruction);
 
   // Try to inline `resolved_method` in place of `invoke_instruction`. `do_rtp` is whether
-  // reference type propagation can run after the inlining.
-  bool TryInline(HInvoke* invoke_instruction, ArtMethod* resolved_method, bool do_rtp = true)
+  // reference type propagation can run after the inlining. If the inlining is successful, this
+  // method will replace and remove the `invoke_instruction`.
+  bool TryInlineAndReplace(HInvoke* invoke_instruction, ArtMethod* resolved_method, bool do_rtp)
     SHARED_REQUIRES(Locks::mutator_lock_);
 
+  bool TryBuildAndInline(HInvoke* invoke_instruction,
+                         ArtMethod* resolved_method,
+                         HInstruction** return_replacement)
+    SHARED_REQUIRES(Locks::mutator_lock_);
+
+  bool TryBuildAndInlineHelper(HInvoke* invoke_instruction,
+                               ArtMethod* resolved_method,
+                               bool same_dex_file,
+                               HInstruction** return_replacement);
+
   // Try to recognize known simple patterns and replace invoke call with appropriate instructions.
-  bool TryPatternSubstitution(HInvoke* invoke_instruction, ArtMethod* resolved_method, bool do_rtp)
+  bool TryPatternSubstitution(HInvoke* invoke_instruction,
+                              ArtMethod* resolved_method,
+                              HInstruction** return_replacement)
     SHARED_REQUIRES(Locks::mutator_lock_);
 
   // Create a new HInstanceFieldGet.
@@ -94,18 +107,13 @@
                                 const InlineCache& ic)
     SHARED_REQUIRES(Locks::mutator_lock_);
 
-  bool TryBuildAndInline(ArtMethod* resolved_method,
-                         HInvoke* invoke_instruction,
-                         bool same_dex_file,
-                         bool do_rtp = true);
-
   HInstanceFieldGet* BuildGetReceiverClass(ClassLinker* class_linker,
                                            HInstruction* receiver,
                                            uint32_t dex_pc) const
     SHARED_REQUIRES(Locks::mutator_lock_);
 
-  void FixUpReturnReferenceType(ArtMethod* resolved_method,
-                                HInvoke* invoke_instruction,
+  void FixUpReturnReferenceType(HInvoke* invoke_instruction,
+                                ArtMethod* resolved_method,
                                 HInstruction* return_replacement,
                                 bool do_rtp)
     SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index ca66f63..27015c0 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2030,13 +2030,6 @@
     }
   }
 
-  if (return_value != nullptr) {
-    invoke->ReplaceWith(return_value);
-  }
-
-  // Finally remove the invoke from the caller.
-  invoke->GetBlock()->RemoveInstruction(invoke);
-
   return return_value;
 }
 
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 18b256f..552d175 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -345,8 +345,9 @@
   void ComputeTryBlockInformation();
 
   // Inline this graph in `outer_graph`, replacing the given `invoke` instruction.
-  // Returns the instruction used to replace the invoke expression or null if the
-  // invoke is for a void method.
+  // Returns the instruction to replace the invoke expression or null if the
+  // invoke is for a void method. Note that the caller is responsible for replacing
+  // and removing the invoke instruction.
   HInstruction* InlineInto(HGraph* outer_graph, HInvoke* invoke);
 
   // Need to add a couple of blocks to test if the loop body is entered and