| Index: src/compiler/structured-machine-assembler.cc | 
| diff --git a/src/compiler/structured-machine-assembler.cc b/src/compiler/structured-machine-assembler.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..3e4c3433d62f1a2c439805cbd6b28f870c334252 | 
| --- /dev/null | 
| +++ b/src/compiler/structured-machine-assembler.cc | 
| @@ -0,0 +1,662 @@ | 
| +// Copyright 2014 the V8 project authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "src/compiler/pipeline.h" | 
| +#include "src/compiler/scheduler.h" | 
| +#include "src/compiler/structured-machine-assembler.h" | 
| + | 
| +namespace v8 { | 
| +namespace internal { | 
| +namespace compiler { | 
| + | 
| +Node* Variable::Get() const { return smasm_->GetVariable(offset_); } | 
| + | 
| + | 
| +void Variable::Set(Node* value) const { smasm_->SetVariable(offset_, value); } | 
| + | 
| + | 
| +StructuredMachineAssembler::StructuredMachineAssembler( | 
| +    Graph* graph, MachineCallDescriptorBuilder* call_descriptor_builder, | 
| +    MachineRepresentation word) | 
| +    : GraphBuilder(graph), | 
| +      schedule_(new (zone()) Schedule(zone())), | 
| +      machine_(zone(), word), | 
| +      common_(zone()), | 
| +      call_descriptor_builder_(call_descriptor_builder), | 
| +      parameters_(NULL), | 
| +      current_environment_(new (zone()) | 
| +                           Environment(zone(), schedule()->entry(), false)), | 
| +      number_of_variables_(0) { | 
| +  if (parameter_count() == 0) return; | 
| +  parameters_ = zone()->NewArray<Node*>(parameter_count()); | 
| +  for (int i = 0; i < parameter_count(); ++i) { | 
| +    parameters_[i] = NewNode(common()->Parameter(i)); | 
| +  } | 
| +} | 
| + | 
| + | 
| +Schedule* StructuredMachineAssembler::Export() { | 
| +  // Compute the correct codegen order. | 
| +  ASSERT(schedule_->rpo_order()->empty()); | 
| +  Scheduler scheduler(zone(), graph(), schedule_); | 
| +  scheduler.ComputeSpecialRPO(); | 
| +  // Invalidate MachineAssembler. | 
| +  Schedule* schedule = schedule_; | 
| +  schedule_ = NULL; | 
| +  return schedule; | 
| +} | 
| + | 
| + | 
| +Node* StructuredMachineAssembler::Parameter(int index) { | 
| +  ASSERT(0 <= index && index < parameter_count()); | 
| +  return parameters_[index]; | 
| +} | 
| + | 
| + | 
| +Node* StructuredMachineAssembler::MakeNode(Operator* op, int input_count, | 
| +                                           Node** inputs) { | 
| +  ASSERT(ScheduleValid()); | 
| +  ASSERT(current_environment_ != NULL); | 
| +  Node* node = graph()->NewNode(op, input_count, inputs); | 
| +  BasicBlock* block = NULL; | 
| +  switch (op->opcode()) { | 
| +    case IrOpcode::kParameter: | 
| +    case IrOpcode::kInt32Constant: | 
| +    case IrOpcode::kInt64Constant: | 
| +    case IrOpcode::kFloat64Constant: | 
| +    case IrOpcode::kExternalConstant: | 
| +    case IrOpcode::kNumberConstant: | 
| +    case IrOpcode::kHeapConstant: | 
| +      // Parameters and constants must be in start. | 
| +      block = schedule()->start(); | 
| +      break; | 
| +    default: | 
| +      // Verify all leaf nodes handled above. | 
| +      ASSERT((op->OutputCount() == 0) == (op->opcode() == IrOpcode::kStore)); | 
| +      block = current_environment_->block_; | 
| +      break; | 
| +  } | 
| +  if (block != NULL) { | 
| +    schedule()->AddNode(block, node); | 
| +  } | 
| +  return node; | 
| +} | 
| + | 
| + | 
| +Variable StructuredMachineAssembler::NewVariable(Node* initial_value) { | 
| +  CHECK(initial_value != NULL); | 
| +  int offset = number_of_variables_++; | 
| +  // Extend current environment to correct number of values. | 
| +  NodeVector* variables = CurrentVars(); | 
| +  size_t to_add = number_of_variables_ - variables->size(); | 
| +  if (to_add != 0) { | 
| +    variables->reserve(number_of_variables_); | 
| +    variables->insert(variables->end(), to_add, NULL); | 
| +  } | 
| +  variables->at(offset) = initial_value; | 
| +  return Variable(this, offset); | 
| +} | 
| + | 
| + | 
| +Node* StructuredMachineAssembler::GetVariable(int offset) { | 
| +  ASSERT(ScheduleValid()); | 
| +  return VariableAt(current_environment_, offset); | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::SetVariable(int offset, Node* value) { | 
| +  ASSERT(ScheduleValid()); | 
| +  Node*& ref = VariableAt(current_environment_, offset); | 
| +  ref = value; | 
| +} | 
| + | 
| + | 
| +Node*& StructuredMachineAssembler::VariableAt(Environment* environment, | 
| +                                              int32_t offset) { | 
| +  // Variable used out of scope. | 
| +  CHECK(static_cast<size_t>(offset) < environment->variables_.size()); | 
| +  Node*& value = environment->variables_.at(offset); | 
| +  CHECK(value != NULL);  // Variable used out of scope. | 
| +  return value; | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::Return(Node* value) { | 
| +  BasicBlock* block = current_environment_->block_; | 
| +  if (block != NULL) { | 
| +    schedule()->AddReturn(block, value); | 
| +  } | 
| +  CopyCurrentAsDead(); | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::CopyCurrentAsDead() { | 
| +  ASSERT(current_environment_ != NULL); | 
| +  bool is_dead = current_environment_->is_dead_; | 
| +  current_environment_->is_dead_ = true; | 
| +  Environment* next = Copy(current_environment_); | 
| +  current_environment_->is_dead_ = is_dead; | 
| +  current_environment_ = next; | 
| +} | 
| + | 
| + | 
| +StructuredMachineAssembler::Environment* StructuredMachineAssembler::Copy( | 
| +    Environment* env, int truncate_at) { | 
| +  Environment* new_env = new (zone()) Environment(zone(), NULL, env->is_dead_); | 
| +  if (!new_env->is_dead_) { | 
| +    new_env->block_ = schedule()->NewBasicBlock(); | 
| +  } | 
| +  new_env->variables_.reserve(truncate_at); | 
| +  NodeVectorIter end = env->variables_.end(); | 
| +  ASSERT(truncate_at <= static_cast<int>(env->variables_.size())); | 
| +  end -= static_cast<int>(env->variables_.size()) - truncate_at; | 
| +  new_env->variables_.insert(new_env->variables_.begin(), | 
| +                             env->variables_.begin(), end); | 
| +  return new_env; | 
| +} | 
| + | 
| + | 
| +StructuredMachineAssembler::Environment* | 
| +StructuredMachineAssembler::CopyForLoopHeader(Environment* env) { | 
| +  Environment* new_env = new (zone()) Environment(zone(), NULL, env->is_dead_); | 
| +  if (!new_env->is_dead_) { | 
| +    new_env->block_ = schedule()->NewBasicBlock(); | 
| +  } | 
| +  new_env->variables_.reserve(env->variables_.size()); | 
| +  for (NodeVectorIter i = env->variables_.begin(); i != env->variables_.end(); | 
| +       ++i) { | 
| +    Node* phi = NULL; | 
| +    if (*i != NULL) { | 
| +      phi = graph()->NewNode(common()->Phi(1), *i); | 
| +      if (new_env->block_ != NULL) { | 
| +        schedule()->AddNode(new_env->block_, phi); | 
| +      } | 
| +    } | 
| +    new_env->variables_.push_back(phi); | 
| +  } | 
| +  return new_env; | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::MergeBackEdgesToLoopHeader( | 
| +    Environment* header, EnvironmentVector* environments) { | 
| +  // Only merge as many variables are were declared before this loop. | 
| +  size_t n = header->variables_.size(); | 
| +  // TODO(dcarney): invert loop order and extend phis once. | 
| +  for (EnvironmentVector::iterator i = environments->begin(); | 
| +       i != environments->end(); ++i) { | 
| +    Environment* from = *i; | 
| +    if (from->is_dead_) continue; | 
| +    AddGoto(from, header); | 
| +    for (size_t i = 0; i < n; ++i) { | 
| +      Node* phi = header->variables_[i]; | 
| +      if (phi == NULL) continue; | 
| +      phi->set_op(common()->Phi(phi->InputCount() + 1)); | 
| +      phi->AppendInput(zone(), VariableAt(from, i)); | 
| +    } | 
| +  } | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::Merge(EnvironmentVector* environments, | 
| +                                       int truncate_at) { | 
| +  ASSERT(current_environment_ == NULL || current_environment_->is_dead_); | 
| +  Environment* next = new (zone()) Environment(zone(), NULL, false); | 
| +  current_environment_ = next; | 
| +  size_t n_vars = number_of_variables_; | 
| +  NodeVector& vars = next->variables_; | 
| +  vars.reserve(n_vars); | 
| +  Node** scratch = NULL; | 
| +  size_t n_envs = environments->size(); | 
| +  Environment** live_environments = reinterpret_cast<Environment**>( | 
| +      alloca(sizeof(environments->at(0)) * n_envs)); | 
| +  size_t n_live = 0; | 
| +  for (size_t i = 0; i < n_envs; i++) { | 
| +    if (environments->at(i)->is_dead_) continue; | 
| +    live_environments[n_live++] = environments->at(i); | 
| +  } | 
| +  n_envs = n_live; | 
| +  if (n_live == 0) next->is_dead_ = true; | 
| +  if (!next->is_dead_) { | 
| +    next->block_ = schedule()->NewBasicBlock(); | 
| +  } | 
| +  for (size_t j = 0; j < n_vars; ++j) { | 
| +    Node* resolved = NULL; | 
| +    // Find first non equal variable. | 
| +    size_t i = 0; | 
| +    for (; i < n_envs; i++) { | 
| +      ASSERT(live_environments[i]->variables_.size() <= n_vars); | 
| +      Node* val = NULL; | 
| +      if (j < static_cast<size_t>(truncate_at)) { | 
| +        val = live_environments[i]->variables_.at(j); | 
| +        // TODO(dcarney): record start position at time of split. | 
| +        //                all variables after this should not be NULL. | 
| +        if (val != NULL) { | 
| +          val = VariableAt(live_environments[i], j); | 
| +        } | 
| +      } | 
| +      if (val == resolved) continue; | 
| +      if (i != 0) break; | 
| +      resolved = val; | 
| +    } | 
| +    // Have to generate a phi. | 
| +    if (i < n_envs) { | 
| +      // All values thus far uninitialized, variable used out of scope. | 
| +      CHECK(resolved != NULL); | 
| +      // Init scratch buffer. | 
| +      if (scratch == NULL) { | 
| +        scratch = static_cast<Node**>(alloca(n_envs * sizeof(resolved))); | 
| +      } | 
| +      for (size_t k = 0; k < i; k++) { | 
| +        scratch[k] = resolved; | 
| +      } | 
| +      for (; i < n_envs; i++) { | 
| +        scratch[i] = live_environments[i]->variables_[j]; | 
| +      } | 
| +      resolved = graph()->NewNode(common()->Phi(n_envs), n_envs, scratch); | 
| +      if (next->block_ != NULL) { | 
| +        schedule()->AddNode(next->block_, resolved); | 
| +      } | 
| +    } | 
| +    vars.push_back(resolved); | 
| +  } | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::AddGoto(Environment* from, Environment* to) { | 
| +  if (to->is_dead_) { | 
| +    ASSERT(from->is_dead_); | 
| +    return; | 
| +  } | 
| +  ASSERT(!from->is_dead_); | 
| +  schedule()->AddGoto(from->block_, to->block_); | 
| +} | 
| + | 
| + | 
| +// TODO(dcarney): add pass before rpo to schedule to compute these. | 
| +BasicBlock* StructuredMachineAssembler::TrampolineFor(BasicBlock* block) { | 
| +  BasicBlock* trampoline = schedule()->NewBasicBlock(); | 
| +  schedule()->AddGoto(trampoline, block); | 
| +  return trampoline; | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::AddBranch(Environment* environment, | 
| +                                           Node* condition, | 
| +                                           Environment* true_val, | 
| +                                           Environment* false_val) { | 
| +  ASSERT(environment->is_dead_ == true_val->is_dead_); | 
| +  ASSERT(environment->is_dead_ == false_val->is_dead_); | 
| +  if (true_val->block_ == false_val->block_) { | 
| +    if (environment->is_dead_) return; | 
| +    AddGoto(environment, true_val); | 
| +    return; | 
| +  } | 
| +  Node* branch = graph()->NewNode(common()->Branch(), condition); | 
| +  if (environment->is_dead_) return; | 
| +  BasicBlock* true_block = TrampolineFor(true_val->block_); | 
| +  BasicBlock* false_block = TrampolineFor(false_val->block_); | 
| +  schedule()->AddBranch(environment->block_, branch, true_block, false_block); | 
| +} | 
| + | 
| + | 
| +StructuredMachineAssembler::Environment::Environment(Zone* zone, | 
| +                                                     BasicBlock* block, | 
| +                                                     bool is_dead) | 
| +    : block_(block), | 
| +      variables_(NodeVector::allocator_type(zone)), | 
| +      is_dead_(is_dead) {} | 
| + | 
| + | 
| +StructuredMachineAssembler::IfBuilder::IfBuilder( | 
| +    StructuredMachineAssembler* smasm) | 
| +    : smasm_(smasm), | 
| +      if_clauses_(IfClauses::allocator_type(smasm_->zone())), | 
| +      pending_exit_merges_(EnvironmentVector::allocator_type(smasm_->zone())) { | 
| +  ASSERT(smasm_->current_environment_ != NULL); | 
| +  PushNewIfClause(); | 
| +  ASSERT(!IsDone()); | 
| +} | 
| + | 
| + | 
| +StructuredMachineAssembler::IfBuilder& | 
| +StructuredMachineAssembler::IfBuilder::If() { | 
| +  ASSERT(smasm_->current_environment_ != NULL); | 
| +  IfClause* clause = CurrentClause(); | 
| +  if (clause->then_environment_ != NULL || clause->else_environment_ != NULL) { | 
| +    PushNewIfClause(); | 
| +  } | 
| +  return *this; | 
| +} | 
| + | 
| + | 
| +StructuredMachineAssembler::IfBuilder& | 
| +StructuredMachineAssembler::IfBuilder::If(Node* condition) { | 
| +  If(); | 
| +  IfClause* clause = CurrentClause(); | 
| +  // Store branch for future resolution. | 
| +  UnresolvedBranch* next = new (smasm_->zone()) | 
| +      UnresolvedBranch(smasm_->current_environment_, condition, NULL); | 
| +  if (clause->unresolved_list_tail_ != NULL) { | 
| +    clause->unresolved_list_tail_->next_ = next; | 
| +  } | 
| +  clause->unresolved_list_tail_ = next; | 
| +  // Push onto merge queues. | 
| +  clause->pending_else_merges_.push_back(next); | 
| +  clause->pending_then_merges_.push_back(next); | 
| +  smasm_->current_environment_ = NULL; | 
| +  return *this; | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::IfBuilder::And() { | 
| +  CurrentClause()->ResolvePendingMerges(smasm_, kCombineThen, kExpressionTerm); | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::IfBuilder::Or() { | 
| +  CurrentClause()->ResolvePendingMerges(smasm_, kCombineElse, kExpressionTerm); | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::IfBuilder::Then() { | 
| +  CurrentClause()->ResolvePendingMerges(smasm_, kCombineThen, kExpressionDone); | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::IfBuilder::Else() { | 
| +  AddCurrentToPending(); | 
| +  CurrentClause()->ResolvePendingMerges(smasm_, kCombineElse, kExpressionDone); | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::IfBuilder::AddCurrentToPending() { | 
| +  if (smasm_->current_environment_ != NULL && | 
| +      !smasm_->current_environment_->is_dead_) { | 
| +    pending_exit_merges_.push_back(smasm_->current_environment_); | 
| +  } | 
| +  smasm_->current_environment_ = NULL; | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::IfBuilder::PushNewIfClause() { | 
| +  int curr_size = | 
| +      static_cast<int>(smasm_->current_environment_->variables_.size()); | 
| +  IfClause* clause = new (smasm_->zone()) IfClause(smasm_->zone(), curr_size); | 
| +  if_clauses_.push_back(clause); | 
| +} | 
| + | 
| + | 
| +StructuredMachineAssembler::IfBuilder::IfClause::IfClause( | 
| +    Zone* zone, int initial_environment_size) | 
| +    : unresolved_list_tail_(NULL), | 
| +      initial_environment_size_(initial_environment_size), | 
| +      expression_states_(ExpressionStates::allocator_type(zone)), | 
| +      pending_then_merges_(PendingMergeStack::allocator_type(zone)), | 
| +      pending_else_merges_(PendingMergeStack::allocator_type(zone)), | 
| +      then_environment_(NULL), | 
| +      else_environment_(NULL) { | 
| +  PushNewExpressionState(); | 
| +} | 
| + | 
| + | 
| +StructuredMachineAssembler::IfBuilder::PendingMergeStackRange | 
| +StructuredMachineAssembler::IfBuilder::IfClause::ComputeRelevantMerges( | 
| +    CombineType combine_type) { | 
| +  ASSERT(!expression_states_.empty()); | 
| +  PendingMergeStack* stack; | 
| +  int start; | 
| +  if (combine_type == kCombineThen) { | 
| +    stack = &pending_then_merges_; | 
| +    start = expression_states_.back().pending_then_size_; | 
| +  } else { | 
| +    ASSERT(combine_type == kCombineElse); | 
| +    stack = &pending_else_merges_; | 
| +    start = expression_states_.back().pending_else_size_; | 
| +  } | 
| +  PendingMergeStackRange data; | 
| +  data.merge_stack_ = stack; | 
| +  data.start_ = start; | 
| +  data.size_ = static_cast<int>(stack->size()) - start; | 
| +  return data; | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::IfBuilder::IfClause::ResolvePendingMerges( | 
| +    StructuredMachineAssembler* smasm, CombineType combine_type, | 
| +    ResolutionType resolution_type) { | 
| +  ASSERT(smasm->current_environment_ == NULL); | 
| +  PendingMergeStackRange data = ComputeRelevantMerges(combine_type); | 
| +  ASSERT_EQ(data.merge_stack_->back(), unresolved_list_tail_); | 
| +  ASSERT(data.size_ > 0); | 
| +  // TODO(dcarney): assert no new variables created during expression building. | 
| +  int truncate_at = initial_environment_size_; | 
| +  if (data.size_ == 1) { | 
| +    // Just copy environment in common case. | 
| +    smasm->current_environment_ = | 
| +        smasm->Copy(unresolved_list_tail_->environment_, truncate_at); | 
| +  } else { | 
| +    EnvironmentVector environments( | 
| +        EnvironmentVector::allocator_type(smasm->zone())); | 
| +    environments.reserve(data.size_); | 
| +    CopyEnvironments(data, &environments); | 
| +    ASSERT(static_cast<int>(environments.size()) == data.size_); | 
| +    smasm->Merge(&environments, truncate_at); | 
| +  } | 
| +  Environment* then_environment = then_environment_; | 
| +  Environment* else_environment = NULL; | 
| +  if (resolution_type == kExpressionDone) { | 
| +    ASSERT(expression_states_.size() == 1); | 
| +    // Set the current then_ or else_environment_ to the new merged environment. | 
| +    if (combine_type == kCombineThen) { | 
| +      ASSERT(then_environment_ == NULL && else_environment_ == NULL); | 
| +      this->then_environment_ = smasm->current_environment_; | 
| +    } else { | 
| +      ASSERT(else_environment_ == NULL); | 
| +      this->else_environment_ = smasm->current_environment_; | 
| +    } | 
| +  } else { | 
| +    ASSERT(resolution_type == kExpressionTerm); | 
| +    ASSERT(then_environment_ == NULL && else_environment_ == NULL); | 
| +  } | 
| +  if (combine_type == kCombineThen) { | 
| +    then_environment = smasm->current_environment_; | 
| +  } else { | 
| +    ASSERT(combine_type == kCombineElse); | 
| +    else_environment = smasm->current_environment_; | 
| +  } | 
| +  // Finalize branches and clear the pending stack. | 
| +  FinalizeBranches(smasm, data, combine_type, then_environment, | 
| +                   else_environment); | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::IfBuilder::IfClause::CopyEnvironments( | 
| +    const PendingMergeStackRange& data, EnvironmentVector* environments) { | 
| +  PendingMergeStack::iterator i = data.merge_stack_->begin(); | 
| +  PendingMergeStack::iterator end = data.merge_stack_->end(); | 
| +  for (i += data.start_; i != end; ++i) { | 
| +    environments->push_back((*i)->environment_); | 
| +  } | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::IfBuilder::IfClause::PushNewExpressionState() { | 
| +  ExpressionState next; | 
| +  next.pending_then_size_ = static_cast<int>(pending_then_merges_.size()); | 
| +  next.pending_else_size_ = static_cast<int>(pending_else_merges_.size()); | 
| +  expression_states_.push_back(next); | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::IfBuilder::IfClause::PopExpressionState() { | 
| +  expression_states_.pop_back(); | 
| +  ASSERT(!expression_states_.empty()); | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::IfBuilder::IfClause::FinalizeBranches( | 
| +    StructuredMachineAssembler* smasm, const PendingMergeStackRange& data, | 
| +    CombineType combine_type, Environment* const then_environment, | 
| +    Environment* const else_environment) { | 
| +  ASSERT(unresolved_list_tail_ != NULL); | 
| +  ASSERT(smasm->current_environment_ != NULL); | 
| +  if (data.size_ == 0) return; | 
| +  PendingMergeStack::iterator curr = data.merge_stack_->begin(); | 
| +  PendingMergeStack::iterator end = data.merge_stack_->end(); | 
| +  // Finalize everything but the head first, | 
| +  // in the order the branches enter the merge block. | 
| +  end -= 1; | 
| +  Environment* true_val = then_environment; | 
| +  Environment* false_val = else_environment; | 
| +  Environment** next; | 
| +  if (combine_type == kCombineThen) { | 
| +    next = &false_val; | 
| +  } else { | 
| +    ASSERT(combine_type == kCombineElse); | 
| +    next = &true_val; | 
| +  } | 
| +  for (curr += data.start_; curr != end; ++curr) { | 
| +    UnresolvedBranch* branch = *curr; | 
| +    *next = branch->next_->environment_; | 
| +    smasm->AddBranch(branch->environment_, branch->condition_, true_val, | 
| +                     false_val); | 
| +  } | 
| +  ASSERT(curr + 1 == data.merge_stack_->end()); | 
| +  // Now finalize the tail if possible. | 
| +  if (then_environment != NULL && else_environment != NULL) { | 
| +    UnresolvedBranch* branch = *curr; | 
| +    smasm->AddBranch(branch->environment_, branch->condition_, then_environment, | 
| +                     else_environment); | 
| +  } | 
| +  // Clear the merge stack. | 
| +  PendingMergeStack::iterator begin = data.merge_stack_->begin(); | 
| +  begin += data.start_; | 
| +  data.merge_stack_->erase(begin, data.merge_stack_->end()); | 
| +  ASSERT_EQ(static_cast<int>(data.merge_stack_->size()), data.start_); | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::IfBuilder::End() { | 
| +  ASSERT(!IsDone()); | 
| +  AddCurrentToPending(); | 
| +  size_t current_pending = pending_exit_merges_.size(); | 
| +  // All unresolved branch edges are now set to pending. | 
| +  for (IfClauses::iterator i = if_clauses_.begin(); i != if_clauses_.end(); | 
| +       ++i) { | 
| +    IfClause* clause = *i; | 
| +    ASSERT(clause->expression_states_.size() == 1); | 
| +    PendingMergeStackRange data; | 
| +    // Copy then environments. | 
| +    data = clause->ComputeRelevantMerges(kCombineThen); | 
| +    clause->CopyEnvironments(data, &pending_exit_merges_); | 
| +    Environment* head = NULL; | 
| +    // Will resolve the head node in the else_merge | 
| +    if (data.size_ > 0 && clause->then_environment_ == NULL && | 
| +        clause->else_environment_ == NULL) { | 
| +      head = pending_exit_merges_.back(); | 
| +      pending_exit_merges_.pop_back(); | 
| +    } | 
| +    // Copy else environments. | 
| +    data = clause->ComputeRelevantMerges(kCombineElse); | 
| +    clause->CopyEnvironments(data, &pending_exit_merges_); | 
| +    if (head != NULL) { | 
| +      // Must have data to merge, or else head will never get a branch. | 
| +      ASSERT(data.size_ != 0); | 
| +      pending_exit_merges_.push_back(head); | 
| +    } | 
| +  } | 
| +  smasm_->Merge(&pending_exit_merges_, | 
| +                if_clauses_[0]->initial_environment_size_); | 
| +  // Anything initally pending jumps into the new environment. | 
| +  for (size_t i = 0; i < current_pending; ++i) { | 
| +    smasm_->AddGoto(pending_exit_merges_[i], smasm_->current_environment_); | 
| +  } | 
| +  // Resolve all branches. | 
| +  for (IfClauses::iterator i = if_clauses_.begin(); i != if_clauses_.end(); | 
| +       ++i) { | 
| +    IfClause* clause = *i; | 
| +    // Must finalize all environments, so ensure they are set correctly. | 
| +    Environment* then_environment = clause->then_environment_; | 
| +    if (then_environment == NULL) { | 
| +      then_environment = smasm_->current_environment_; | 
| +    } | 
| +    Environment* else_environment = clause->else_environment_; | 
| +    PendingMergeStackRange data; | 
| +    // Finalize then environments. | 
| +    data = clause->ComputeRelevantMerges(kCombineThen); | 
| +    clause->FinalizeBranches(smasm_, data, kCombineThen, then_environment, | 
| +                             else_environment); | 
| +    // Finalize else environments. | 
| +    // Now set the else environment so head is finalized for edge case above. | 
| +    if (else_environment == NULL) { | 
| +      else_environment = smasm_->current_environment_; | 
| +    } | 
| +    data = clause->ComputeRelevantMerges(kCombineElse); | 
| +    clause->FinalizeBranches(smasm_, data, kCombineElse, then_environment, | 
| +                             else_environment); | 
| +  } | 
| +  // Future accesses to this builder should crash immediately. | 
| +  pending_exit_merges_.clear(); | 
| +  if_clauses_.clear(); | 
| +  ASSERT(IsDone()); | 
| +} | 
| + | 
| + | 
| +StructuredMachineAssembler::LoopBuilder::LoopBuilder( | 
| +    StructuredMachineAssembler* smasm) | 
| +    : smasm_(smasm), | 
| +      header_environment_(NULL), | 
| +      pending_header_merges_(EnvironmentVector::allocator_type(smasm_->zone())), | 
| +      pending_exit_merges_(EnvironmentVector::allocator_type(smasm_->zone())) { | 
| +  ASSERT(smasm_->current_environment_ != NULL); | 
| +  // Create header environment. | 
| +  header_environment_ = smasm_->CopyForLoopHeader(smasm_->current_environment_); | 
| +  smasm_->AddGoto(smasm_->current_environment_, header_environment_); | 
| +  // Create body environment. | 
| +  Environment* body = smasm_->Copy(header_environment_); | 
| +  smasm_->AddGoto(header_environment_, body); | 
| +  smasm_->current_environment_ = body; | 
| +  ASSERT(!IsDone()); | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::LoopBuilder::Continue() { | 
| +  ASSERT(!IsDone()); | 
| +  pending_header_merges_.push_back(smasm_->current_environment_); | 
| +  smasm_->CopyCurrentAsDead(); | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::LoopBuilder::Break() { | 
| +  ASSERT(!IsDone()); | 
| +  pending_exit_merges_.push_back(smasm_->current_environment_); | 
| +  smasm_->CopyCurrentAsDead(); | 
| +} | 
| + | 
| + | 
| +void StructuredMachineAssembler::LoopBuilder::End() { | 
| +  ASSERT(!IsDone()); | 
| +  if (smasm_->current_environment_ != NULL) { | 
| +    Continue(); | 
| +  } | 
| +  // Do loop header merges. | 
| +  smasm_->MergeBackEdgesToLoopHeader(header_environment_, | 
| +                                     &pending_header_merges_); | 
| +  int initial_size = header_environment_->variables_.size(); | 
| +  // Do loop exit merges, truncating loop variables away. | 
| +  smasm_->Merge(&pending_exit_merges_, initial_size); | 
| +  for (EnvironmentVector::iterator i = pending_exit_merges_.begin(); | 
| +       i != pending_exit_merges_.end(); ++i) { | 
| +    smasm_->AddGoto(*i, smasm_->current_environment_); | 
| +  } | 
| +  pending_header_merges_.clear(); | 
| +  pending_exit_merges_.clear(); | 
| +  header_environment_ = NULL; | 
| +  ASSERT(IsDone()); | 
| +} | 
| + | 
| +}  // namespace compiler | 
| +}  // namespace internal | 
| +}  // namespace v8 | 
|  |