Fix ids and remove invoke when inlining.

Bugs found by Razvan Lupusoru.

Change-Id: I3a5a9af280d8700d18f52abb4a2cff0e3a9aac74
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 5d712fe..e55175f 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -16,9 +16,9 @@
 
 #include "graph_checker.h"
 
-#include <string>
 #include <map>
 #include <sstream>
+#include <string>
 
 #include "base/bit_vector-inl.h"
 
@@ -123,6 +123,14 @@
 }
 
 void GraphChecker::VisitInstruction(HInstruction* instruction) {
+  if (seen_ids_.IsBitSet(instruction->GetId())) {
+    std::stringstream error;
+    error << "Duplicate id in graph " << instruction->GetId() << ".";
+    errors_.push_back(error.str());
+  } else {
+    seen_ids_.SetBit(instruction->GetId());
+  }
+
   // Ensure `instruction` is associated with `current_block_`.
   if (instruction->GetBlock() != current_block_) {
     std::stringstream error;
diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h
index b6c9f17..ba60cb9 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -30,7 +30,8 @@
                const char* dump_prefix = "art::GraphChecker: ")
     : HGraphDelegateVisitor(graph),
       allocator_(allocator),
-      dump_prefix_(dump_prefix) {}
+      dump_prefix_(dump_prefix),
+      seen_ids_(allocator, graph->GetCurrentInstructionId(), false) {}
 
   // Check the whole graph (in insertion order).
   virtual void Run() { VisitInsertionOrder(); }
@@ -68,6 +69,7 @@
  private:
   // String displayed before dumped errors.
   const char* const dump_prefix_;
+  ArenaBitVector seen_ids_;
 
   DISALLOW_COPY_AND_ASSIGN(GraphChecker);
 };
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 1de5b78..73eb521 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -200,6 +200,11 @@
   }
 
   callee_graph->InlineInto(graph_, invoke_instruction);
+
+  // Now that we have inlined the callee, we need to update the next
+  // instruction id of the caller, so that new instructions added
+  // after optimizations get a unique id.
+  graph_->SetCurrentInstructionId(callee_graph->GetNextInstructionId());
   VLOG(compiler) << "Successfully inlined " << PrettyMethod(method_index, outer_dex_file);
   outer_stats_->RecordStat(kInlinedInvoke);
   return true;
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index fb941b5..4133cf6 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -750,13 +750,16 @@
     }
   }
 
-  // Finally, replace the invoke with the return value of the inlined graph.
+  // Replace the invoke with the return value of the inlined graph.
   if (last->IsReturn()) {
     invoke->ReplaceWith(last->InputAt(0));
     body->RemoveInstruction(last);
   } else {
     DCHECK(last->IsReturnVoid());
   }
+
+  // Finally remove the invoke from the caller.
+  invoke->GetBlock()->RemoveInstruction(invoke);
 }
 
 }  // namespace art