Revert "Revert "ART: Implement try/catch blocks in Builder""

This patch enables the GraphBuilder to generate blocks and edges which
represent the exceptional control flow when try/catch blocks are
present in the code. Actual compilation is still delegated to Quick
and Baseline ignores the additional code.

To represent the relationship between try and catch blocks, Builder
splits the edges which enter/exit a try block and links the newly
created blocks to the corresponding exception handlers. This layout
will later enable the SsaBuilder to correctly infer the dominators of
the catch blocks and to produce the appropriate reverse post ordering.
It will not, however, allow for building the complete SSA form of the
catch blocks and consequently optimizing such blocks.

To this end, a new TryBoundary control-flow instruction is introduced.
Codegen treats it the same as a Goto but it allows for additional
successors (the handlers).

This reverts commit 3e18738bd338e9f8363b26bc895f38c0ec682824.

Change-Id: I4f5ea961848a0b83d8db3673763861633e9bfcfb
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 0f5b1ab..f2e9e22 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -39,6 +39,7 @@
 class HDoubleConstant;
 class HEnvironment;
 class HFloatConstant;
+class HGraphBuilder;
 class HGraphVisitor;
 class HInstruction;
 class HIntConstant;
@@ -207,6 +208,12 @@
   // Removes `block` from the graph.
   void DeleteDeadBlock(HBasicBlock* block);
 
+  // Splits the edge between `block` and `successor` while preserving the
+  // indices in the predecessor/successor lists. If there are multiple edges
+  // between the blocks, the lowest indices are used.
+  // Returns the new block which is empty and has the same dex pc as `successor`.
+  HBasicBlock* SplitEdge(HBasicBlock* block, HBasicBlock* successor);
+
   void SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor);
   void SimplifyLoop(HBasicBlock* header);
 
@@ -566,6 +573,15 @@
   }
 
   bool IsSingleGoto() const;
+  bool IsSingleTryBoundary() const;
+
+  // Returns true if this block emits nothing but a jump.
+  bool IsSingleJump() const {
+    HLoopInformation* loop_info = GetLoopInformation();
+    return (IsSingleGoto() || IsSingleTryBoundary())
+           // Back edges generate a suspend check.
+           && (loop_info == nullptr || !loop_info->IsBackEdge(*this));
+  }
 
   void AddBackEdge(HBasicBlock* back_edge) {
     if (loop_information_ == nullptr) {
@@ -674,7 +690,7 @@
     successors_.Put(1, temp);
   }
 
-  size_t GetPredecessorIndexOf(HBasicBlock* predecessor) {
+  size_t GetPredecessorIndexOf(HBasicBlock* predecessor) const {
     for (size_t i = 0, e = predecessors_.Size(); i < e; ++i) {
       if (predecessors_.Get(i) == predecessor) {
         return i;
@@ -683,7 +699,7 @@
     return -1;
   }
 
-  size_t GetSuccessorIndexOf(HBasicBlock* successor) {
+  size_t GetSuccessorIndexOf(HBasicBlock* successor) const {
     for (size_t i = 0, e = successors_.Size(); i < e; ++i) {
       if (successors_.Get(i) == successor) {
         return i;
@@ -692,6 +708,32 @@
     return -1;
   }
 
+  HBasicBlock* GetSinglePredecessor() const {
+    DCHECK_EQ(GetPredecessors().Size(), 1u);
+    return GetPredecessors().Get(0);
+  }
+
+  HBasicBlock* GetSingleSuccessor() const {
+    DCHECK_EQ(GetSuccessors().Size(), 1u);
+    return GetSuccessors().Get(0);
+  }
+
+  // Returns whether the first occurrence of `predecessor` in the list of
+  // predecessors is at index `idx`.
+  bool IsFirstIndexOfPredecessor(HBasicBlock* predecessor, size_t idx) const {
+    DCHECK_EQ(GetPredecessors().Get(idx), predecessor);
+    return GetPredecessorIndexOf(predecessor) == idx;
+  }
+
+  // Returns whether successor at index `idx` is an exception handler.
+  bool IsExceptionalSuccessor(size_t idx) const;
+
+  // Split the block into two blocks just before `cursor`. Returns the newly
+  // created, latter block. Note that this method will create a Goto at the end
+  // of the former block and will create an edge between them. It will not,
+  // however, update the graph, reverse post order or loop information.
+  HBasicBlock* SplitBefore(HInstruction* cursor);
+
   // Split the block into two blocks just after `cursor`. Returns the newly
   // created block. Note that this method just updates raw block information,
   // like predecessors, successors, dominators, and instruction list. It does not
@@ -913,6 +955,7 @@
   M(SuspendCheck, Instruction)                                          \
   M(Temporary, Instruction)                                             \
   M(Throw, Instruction)                                                 \
+  M(TryBoundary, Instruction)                                           \
   M(TypeConversion, Instruction)                                        \
   M(UShr, BinaryOperation)                                              \
   M(Xor, BinaryOperation)                                               \
@@ -1858,7 +1901,7 @@
   bool IsControlFlow() const OVERRIDE { return true; }
 
   HBasicBlock* GetSuccessor() const {
-    return GetBlock()->GetSuccessors().Get(0);
+    return GetBlock()->GetSingleSuccessor();
   }
 
   DECLARE_INSTRUCTION(Goto);
@@ -1892,6 +1935,65 @@
   DISALLOW_COPY_AND_ASSIGN(HIf);
 };
 
+
+// Abstract instruction which marks the beginning and/or end of a try block and
+// links it to the respective exception handlers. Behaves the same as a Goto in
+// non-exceptional control flow.
+// Normal-flow successor is stored at index zero, exception handlers under
+// higher indices in no particular order.
+class HTryBoundary : public HTemplateInstruction<0> {
+ public:
+  HTryBoundary(bool is_entry, bool is_exit)
+      : HTemplateInstruction(SideEffects::None()), is_entry_(is_entry), is_exit_(is_exit) {}
+
+  bool IsControlFlow() const OVERRIDE { return true; }
+
+  // Returns the block's non-exceptional successor (index zero).
+  HBasicBlock* GetNormalFlowSuccessor() const { return GetBlock()->GetSuccessors().Get(0); }
+
+  // Returns whether `handler` is among its exception handlers (non-zero index
+  // successors).
+  bool HasExceptionHandler(HBasicBlock* handler) const {
+    DCHECK(handler->IsCatchBlock());
+    return GetBlock()->GetSuccessors().Contains(handler, /* start_from */ 1);
+  }
+
+  // Returns whether successor at index `idx` is an exception handler.
+  bool IsExceptionalSuccessor(size_t idx) const {
+    DCHECK_LT(idx, GetBlock()->GetSuccessors().Size());
+    bool is_handler = (idx != 0);
+    DCHECK(!is_handler || GetBlock()->GetSuccessors().Get(idx)->IsCatchBlock());
+    return is_handler;
+  }
+
+  // If not present already, adds `handler` to its block's list of exception
+  // handlers.
+  void AddExceptionHandler(HBasicBlock* handler) {
+    if (!HasExceptionHandler(handler)) {
+      GetBlock()->AddSuccessor(handler);
+    }
+  }
+
+  bool IsTryEntry() const { return is_entry_; }
+  bool IsTryExit() const { return is_exit_; }
+
+  DECLARE_INSTRUCTION(TryBoundary);
+
+ private:
+  // Only for debugging purposes.
+  bool is_entry_;
+  bool is_exit_;
+
+  // Only set by HGraphBuilder.
+  void SetIsTryEntry() { is_entry_ = true; }
+  void SetIsTryExit() { is_exit_ = true; }
+
+  friend HGraphBuilder;
+
+  DISALLOW_COPY_AND_ASSIGN(HTryBoundary);
+};
+
+
 // Deoptimize to interpreter, upon checking a condition.
 class HDeoptimize : public HTemplateInstruction<1> {
  public: