| 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
|
|
|