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 |