Merge "ART: Fix overlapping instruction IDs in inliner"
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 3f67e48..3e3719e 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1010,6 +1010,8 @@
     // at runtime, we change this call as if it was a virtual call.
     invoke_type = kVirtual;
   }
+
+  const int32_t caller_instruction_counter = graph_->GetCurrentInstructionId();
   HGraph* callee_graph = new (graph_->GetArena()) HGraph(
       graph_->GetArena(),
       callee_dex_file,
@@ -1019,7 +1021,7 @@
       invoke_type,
       graph_->IsDebuggable(),
       /* osr */ false,
-      graph_->GetCurrentInstructionId());
+      caller_instruction_counter);
   callee_graph->SetArtMethod(resolved_method);
 
   OptimizingCompilerStats inline_stats;
@@ -1219,7 +1221,16 @@
   }
   number_of_inlined_instructions_ += number_of_instructions;
 
+  DCHECK_EQ(caller_instruction_counter, graph_->GetCurrentInstructionId())
+      << "No instructions can be added to the outer graph while inner graph is being built";
+
+  const int32_t callee_instruction_counter = callee_graph->GetCurrentInstructionId();
+  graph_->SetCurrentInstructionId(callee_instruction_counter);
   *return_replacement = callee_graph->InlineInto(graph_, invoke_instruction);
+
+  DCHECK_EQ(callee_instruction_counter, callee_graph->GetCurrentInstructionId())
+      << "No instructions can be added to the inner graph during inlining into the outer graph";
+
   return true;
 }
 
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 87b9c02..0e0b83e 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -1976,34 +1976,6 @@
     at->MergeWithInlined(first);
     exit_block_->ReplaceWith(to);
 
-    // Update all predecessors of the exit block (now the `to` block)
-    // to not `HReturn` but `HGoto` instead.
-    bool returns_void = to->GetPredecessors()[0]->GetLastInstruction()->IsReturnVoid();
-    if (to->GetPredecessors().size() == 1) {
-      HBasicBlock* predecessor = to->GetPredecessors()[0];
-      HInstruction* last = predecessor->GetLastInstruction();
-      if (!returns_void) {
-        return_value = last->InputAt(0);
-      }
-      predecessor->AddInstruction(new (allocator) HGoto(last->GetDexPc()));
-      predecessor->RemoveInstruction(last);
-    } else {
-      if (!returns_void) {
-        // There will be multiple returns.
-        return_value = new (allocator) HPhi(
-            allocator, kNoRegNumber, 0, HPhi::ToPhiType(invoke->GetType()), to->GetDexPc());
-        to->AddPhi(return_value->AsPhi());
-      }
-      for (HBasicBlock* predecessor : to->GetPredecessors()) {
-        HInstruction* last = predecessor->GetLastInstruction();
-        if (!returns_void) {
-          return_value->AsPhi()->AddInput(last->InputAt(0));
-        }
-        predecessor->AddInstruction(new (allocator) HGoto(last->GetDexPc()));
-        predecessor->RemoveInstruction(last);
-      }
-    }
-
     // Update the meta information surrounding blocks:
     // (1) the graph they are now in,
     // (2) the reverse post order of that graph,
@@ -2048,11 +2020,36 @@
     // Only `to` can become a back edge, as the inlined blocks
     // are predecessors of `to`.
     UpdateLoopAndTryInformationOfNewBlock(to, at, /* replace_if_back_edge */ true);
-  }
 
-  // Update the next instruction id of the outer graph, so that instructions
-  // added later get bigger ids than those in the inner graph.
-  outer_graph->SetCurrentInstructionId(GetNextInstructionId());
+    // Update all predecessors of the exit block (now the `to` block)
+    // to not `HReturn` but `HGoto` instead.
+    bool returns_void = to->GetPredecessors()[0]->GetLastInstruction()->IsReturnVoid();
+    if (to->GetPredecessors().size() == 1) {
+      HBasicBlock* predecessor = to->GetPredecessors()[0];
+      HInstruction* last = predecessor->GetLastInstruction();
+      if (!returns_void) {
+        return_value = last->InputAt(0);
+      }
+      predecessor->AddInstruction(new (allocator) HGoto(last->GetDexPc()));
+      predecessor->RemoveInstruction(last);
+    } else {
+      if (!returns_void) {
+        // There will be multiple returns.
+        return_value = new (allocator) HPhi(
+            allocator, kNoRegNumber, 0, HPhi::ToPhiType(invoke->GetType()), to->GetDexPc());
+        to->AddPhi(return_value->AsPhi());
+      }
+      for (HBasicBlock* predecessor : to->GetPredecessors()) {
+        HInstruction* last = predecessor->GetLastInstruction();
+        if (!returns_void) {
+          DCHECK(last->IsReturn());
+          return_value->AsPhi()->AddInput(last->InputAt(0));
+        }
+        predecessor->AddInstruction(new (allocator) HGoto(last->GetDexPc()));
+        predecessor->RemoveInstruction(last);
+      }
+    }
+  }
 
   // Walk over the entry block and:
   // - Move constants from the entry block to the outer_graph's entry block,
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index e3dbe16..b684cc6 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -387,6 +387,7 @@
   }
 
   void SetCurrentInstructionId(int32_t id) {
+    DCHECK_GE(id, current_instruction_id_);
     current_instruction_id_ = id;
   }