| Index: src/compiler/scheduler.cc
 | 
| diff --git a/src/compiler/scheduler.cc b/src/compiler/scheduler.cc
 | 
| index 6e105e37131a3a326a9c4b97ce8e640dfc988259..8cbc05ebf71f6cc9bc3496e77de4069ba6020f59 100644
 | 
| --- a/src/compiler/scheduler.cc
 | 
| +++ b/src/compiler/scheduler.cc
 | 
| @@ -286,7 +286,7 @@ class CFGBuilder : public ZoneObject {
 | 
|    }
 | 
|  
 | 
|   private:
 | 
| -  // TODO(mstarzinger): Only for Scheduler::FuseFloatingControl.
 | 
| +  friend class ScheduleLateNodeVisitor;
 | 
|    friend class Scheduler;
 | 
|  
 | 
|    void FixNode(BasicBlock* block, Node* node) {
 | 
| @@ -320,6 +320,11 @@ class CFGBuilder : public ZoneObject {
 | 
|        case IrOpcode::kSwitch:
 | 
|          BuildBlocksForSuccessors(node);
 | 
|          break;
 | 
| +      case IrOpcode::kCall:
 | 
| +        if (IsExceptionalCall(node)) {
 | 
| +          BuildBlocksForSuccessors(node);
 | 
| +        }
 | 
| +        break;
 | 
|        default:
 | 
|          break;
 | 
|      }
 | 
| @@ -347,6 +352,12 @@ class CFGBuilder : public ZoneObject {
 | 
|          scheduler_->UpdatePlacement(node, Scheduler::kFixed);
 | 
|          ConnectThrow(node);
 | 
|          break;
 | 
| +      case IrOpcode::kCall:
 | 
| +        if (IsExceptionalCall(node)) {
 | 
| +          scheduler_->UpdatePlacement(node, Scheduler::kFixed);
 | 
| +          ConnectCall(node);
 | 
| +        }
 | 
| +        break;
 | 
|        default:
 | 
|          break;
 | 
|      }
 | 
| @@ -381,6 +392,31 @@ class CFGBuilder : public ZoneObject {
 | 
|      }
 | 
|    }
 | 
|  
 | 
| +  BasicBlock* FindPredecessorBlock(Node* node) {
 | 
| +    BasicBlock* predecessor_block = nullptr;
 | 
| +    while (true) {
 | 
| +      predecessor_block = schedule_->block(node);
 | 
| +      if (predecessor_block != nullptr) break;
 | 
| +      node = NodeProperties::GetControlInput(node);
 | 
| +    }
 | 
| +    return predecessor_block;
 | 
| +  }
 | 
| +
 | 
| +  void ConnectCall(Node* call) {
 | 
| +    BasicBlock* successor_blocks[2];
 | 
| +    CollectSuccessorBlocks(call, successor_blocks, arraysize(successor_blocks));
 | 
| +
 | 
| +    // Consider the exception continuation to be deferred.
 | 
| +    successor_blocks[1]->set_deferred(true);
 | 
| +
 | 
| +    Node* call_control = NodeProperties::GetControlInput(call);
 | 
| +    BasicBlock* call_block = FindPredecessorBlock(call_control);
 | 
| +    TraceConnect(call, call_block, successor_blocks[0]);
 | 
| +    TraceConnect(call, call_block, successor_blocks[1]);
 | 
| +    schedule_->AddCall(call_block, call, successor_blocks[0],
 | 
| +                       successor_blocks[1]);
 | 
| +  }
 | 
| +
 | 
|    void ConnectBranch(Node* branch) {
 | 
|      BasicBlock* successor_blocks[2];
 | 
|      CollectSuccessorBlocks(branch, successor_blocks,
 | 
| @@ -404,10 +440,8 @@ class CFGBuilder : public ZoneObject {
 | 
|        schedule_->InsertBranch(component_start_, component_end_, branch,
 | 
|                                successor_blocks[0], successor_blocks[1]);
 | 
|      } else {
 | 
| -      Node* branch_block_node = NodeProperties::GetControlInput(branch);
 | 
| -      BasicBlock* branch_block = schedule_->block(branch_block_node);
 | 
| -      DCHECK_NOT_NULL(branch_block);
 | 
| -
 | 
| +      Node* branch_control = NodeProperties::GetControlInput(branch);
 | 
| +      BasicBlock* branch_block = FindPredecessorBlock(branch_control);
 | 
|        TraceConnect(branch, branch_block, successor_blocks[0]);
 | 
|        TraceConnect(branch, branch_block, successor_blocks[1]);
 | 
|        schedule_->AddBranch(branch_block, branch, successor_blocks[0],
 | 
| @@ -428,14 +462,12 @@ class CFGBuilder : public ZoneObject {
 | 
|        schedule_->InsertSwitch(component_start_, component_end_, sw,
 | 
|                                successor_blocks, successor_count);
 | 
|      } else {
 | 
| -      Node* sw_block_node = NodeProperties::GetControlInput(sw);
 | 
| -      BasicBlock* sw_block = schedule_->block(sw_block_node);
 | 
| -      DCHECK_NOT_NULL(sw_block);
 | 
| -
 | 
| +      Node* switch_control = NodeProperties::GetControlInput(sw);
 | 
| +      BasicBlock* switch_block = FindPredecessorBlock(switch_control);
 | 
|        for (size_t index = 0; index < successor_count; ++index) {
 | 
| -        TraceConnect(sw, sw_block, successor_blocks[index]);
 | 
| +        TraceConnect(sw, switch_block, successor_blocks[index]);
 | 
|        }
 | 
| -      schedule_->AddSwitch(sw_block, sw, successor_blocks, successor_count);
 | 
| +      schedule_->AddSwitch(switch_block, sw, successor_blocks, successor_count);
 | 
|      }
 | 
|    }
 | 
|  
 | 
| @@ -448,22 +480,22 @@ class CFGBuilder : public ZoneObject {
 | 
|      // For all of the merge's control inputs, add a goto at the end to the
 | 
|      // merge's basic block.
 | 
|      for (Node* const input : merge->inputs()) {
 | 
| -      BasicBlock* predecessor_block = schedule_->block(input);
 | 
| +      BasicBlock* predecessor_block = FindPredecessorBlock(input);
 | 
|        TraceConnect(merge, predecessor_block, block);
 | 
|        schedule_->AddGoto(predecessor_block, block);
 | 
|      }
 | 
|    }
 | 
|  
 | 
|    void ConnectReturn(Node* ret) {
 | 
| -    Node* return_block_node = NodeProperties::GetControlInput(ret);
 | 
| -    BasicBlock* return_block = schedule_->block(return_block_node);
 | 
| +    Node* return_control = NodeProperties::GetControlInput(ret);
 | 
| +    BasicBlock* return_block = FindPredecessorBlock(return_control);
 | 
|      TraceConnect(ret, return_block, NULL);
 | 
|      schedule_->AddReturn(return_block, ret);
 | 
|    }
 | 
|  
 | 
|    void ConnectThrow(Node* thr) {
 | 
| -    Node* throw_block_node = NodeProperties::GetControlInput(thr);
 | 
| -    BasicBlock* throw_block = schedule_->block(throw_block_node);
 | 
| +    Node* throw_control = NodeProperties::GetControlInput(thr);
 | 
| +    BasicBlock* throw_block = FindPredecessorBlock(throw_control);
 | 
|      TraceConnect(thr, throw_block, NULL);
 | 
|      schedule_->AddThrow(throw_block, thr);
 | 
|    }
 | 
| @@ -479,6 +511,13 @@ class CFGBuilder : public ZoneObject {
 | 
|      }
 | 
|    }
 | 
|  
 | 
| +  bool IsExceptionalCall(Node* node) {
 | 
| +    for (Node* const use : node->uses()) {
 | 
| +      if (use->opcode() == IrOpcode::kIfException) return true;
 | 
| +    }
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
|    bool IsFinalMerge(Node* node) {
 | 
|      return (node->opcode() == IrOpcode::kMerge &&
 | 
|              node == scheduler_->graph_->end()->InputAt(0));
 | 
| @@ -1324,7 +1363,7 @@ class ScheduleLateNodeVisitor {
 | 
|      }
 | 
|  
 | 
|      // Schedule the node or a floating control structure.
 | 
| -    if (NodeProperties::IsControl(node)) {
 | 
| +    if (IrOpcode::IsMergeOpcode(node->opcode())) {
 | 
|        ScheduleFloatingControl(block, node);
 | 
|      } else {
 | 
|        ScheduleNode(block, node);
 | 
| @@ -1448,10 +1487,13 @@ class ScheduleLateNodeVisitor {
 | 
|      return block;
 | 
|    }
 | 
|  
 | 
| +  BasicBlock* FindPredecessorBlock(Node* node) {
 | 
| +    return scheduler_->control_flow_builder_->FindPredecessorBlock(node);
 | 
| +  }
 | 
| +
 | 
|    BasicBlock* GetBlockForUse(Edge edge) {
 | 
|      Node* use = edge.from();
 | 
| -    IrOpcode::Value opcode = use->opcode();
 | 
| -    if (IrOpcode::IsPhiOpcode(opcode)) {
 | 
| +    if (IrOpcode::IsPhiOpcode(use->opcode())) {
 | 
|        // If the use is from a coupled (i.e. floating) phi, compute the common
 | 
|        // dominator of its uses. This will not recurse more than one level.
 | 
|        if (scheduler_->GetPlacement(use) == Scheduler::kCoupled) {
 | 
| @@ -1460,15 +1502,23 @@ class ScheduleLateNodeVisitor {
 | 
|          DCHECK_EQ(edge.to(), NodeProperties::GetControlInput(use));
 | 
|          return GetCommonDominatorOfUses(use);
 | 
|        }
 | 
| -      // If the use is from a fixed (i.e. non-floating) phi, use the block
 | 
| -      // of the corresponding control input to the merge.
 | 
| +      // If the use is from a fixed (i.e. non-floating) phi, we use the
 | 
| +      // predecessor block of the corresponding control input to the merge.
 | 
|        if (scheduler_->GetPlacement(use) == Scheduler::kFixed) {
 | 
|          Trace("  input@%d into a fixed phi #%d:%s\n", edge.index(), use->id(),
 | 
|                use->op()->mnemonic());
 | 
|          Node* merge = NodeProperties::GetControlInput(use, 0);
 | 
| -        opcode = merge->opcode();
 | 
| -        DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop);
 | 
| -        use = NodeProperties::GetControlInput(merge, edge.index());
 | 
| +        DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
 | 
| +        Node* input = NodeProperties::GetControlInput(merge, edge.index());
 | 
| +        return FindPredecessorBlock(input);
 | 
| +      }
 | 
| +    } else if (IrOpcode::IsMergeOpcode(use->opcode())) {
 | 
| +      // If the use is from a fixed (i.e. non-floating) merge, we use the
 | 
| +      // predecessor block of the current input to the merge.
 | 
| +      if (scheduler_->GetPlacement(use) == Scheduler::kFixed) {
 | 
| +        Trace("  input@%d into a fixed merge #%d:%s\n", edge.index(), use->id(),
 | 
| +              use->op()->mnemonic());
 | 
| +        return FindPredecessorBlock(edge.to());
 | 
|        }
 | 
|      }
 | 
|      BasicBlock* result = schedule_->block(use);
 | 
| 
 |