| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "src/compiler/pipeline.h" | |
| 6 #include "src/compiler/scheduler.h" | |
| 7 #include "test/cctest/compiler/structured-machine-assembler.h" | |
| 8 | |
| 9 namespace v8 { | |
| 10 namespace internal { | |
| 11 namespace compiler { | |
| 12 | |
| 13 Node* Variable::Get() const { return smasm_->GetVariable(offset_); } | |
| 14 | |
| 15 | |
| 16 void Variable::Set(Node* value) const { smasm_->SetVariable(offset_, value); } | |
| 17 | |
| 18 | |
| 19 StructuredMachineAssembler::StructuredMachineAssembler( | |
| 20 Graph* graph, MachineSignature* machine_sig, MachineType word) | |
| 21 : RawMachineAssembler(graph, machine_sig, word), | |
| 22 current_environment_(new (zone()) | |
| 23 Environment(zone(), schedule()->start(), false)), | |
| 24 number_of_variables_(0) {} | |
| 25 | |
| 26 | |
| 27 Node* StructuredMachineAssembler::MakeNode(Operator* op, int input_count, | |
| 28 Node** inputs) { | |
| 29 DCHECK(ScheduleValid()); | |
| 30 DCHECK(current_environment_ != NULL); | |
| 31 Node* node = graph()->NewNode(op, input_count, inputs); | |
| 32 BasicBlock* block = NULL; | |
| 33 switch (op->opcode()) { | |
| 34 case IrOpcode::kParameter: | |
| 35 case IrOpcode::kInt32Constant: | |
| 36 case IrOpcode::kInt64Constant: | |
| 37 case IrOpcode::kFloat64Constant: | |
| 38 case IrOpcode::kExternalConstant: | |
| 39 case IrOpcode::kNumberConstant: | |
| 40 case IrOpcode::kHeapConstant: | |
| 41 // Parameters and constants must be in start. | |
| 42 block = schedule()->start(); | |
| 43 break; | |
| 44 default: | |
| 45 // Verify all leaf nodes handled above. | |
| 46 DCHECK((op->OutputCount() == 0) == (op->opcode() == IrOpcode::kStore)); | |
| 47 block = current_environment_->block_; | |
| 48 break; | |
| 49 } | |
| 50 if (block != NULL) { | |
| 51 schedule()->AddNode(block, node); | |
| 52 } | |
| 53 return node; | |
| 54 } | |
| 55 | |
| 56 | |
| 57 Variable StructuredMachineAssembler::NewVariable(Node* initial_value) { | |
| 58 CHECK(initial_value != NULL); | |
| 59 int offset = number_of_variables_++; | |
| 60 // Extend current environment to correct number of values. | |
| 61 NodeVector* variables = CurrentVars(); | |
| 62 size_t to_add = number_of_variables_ - variables->size(); | |
| 63 if (to_add != 0) { | |
| 64 variables->reserve(number_of_variables_); | |
| 65 variables->insert(variables->end(), to_add, NULL); | |
| 66 } | |
| 67 variables->at(offset) = initial_value; | |
| 68 return Variable(this, offset); | |
| 69 } | |
| 70 | |
| 71 | |
| 72 Node* StructuredMachineAssembler::GetVariable(int offset) { | |
| 73 DCHECK(ScheduleValid()); | |
| 74 return VariableAt(current_environment_, offset); | |
| 75 } | |
| 76 | |
| 77 | |
| 78 void StructuredMachineAssembler::SetVariable(int offset, Node* value) { | |
| 79 DCHECK(ScheduleValid()); | |
| 80 Node*& ref = VariableAt(current_environment_, offset); | |
| 81 ref = value; | |
| 82 } | |
| 83 | |
| 84 | |
| 85 Node*& StructuredMachineAssembler::VariableAt(Environment* environment, | |
| 86 int32_t offset) { | |
| 87 // Variable used out of scope. | |
| 88 CHECK(static_cast<size_t>(offset) < environment->variables_.size()); | |
| 89 Node*& value = environment->variables_.at(offset); | |
| 90 CHECK(value != NULL); // Variable used out of scope. | |
| 91 return value; | |
| 92 } | |
| 93 | |
| 94 | |
| 95 void StructuredMachineAssembler::Return(Node* value) { | |
| 96 BasicBlock* block = current_environment_->block_; | |
| 97 if (block != NULL) { | |
| 98 schedule()->AddReturn(block, value); | |
| 99 } | |
| 100 CopyCurrentAsDead(); | |
| 101 } | |
| 102 | |
| 103 | |
| 104 void StructuredMachineAssembler::CopyCurrentAsDead() { | |
| 105 DCHECK(current_environment_ != NULL); | |
| 106 bool is_dead = current_environment_->is_dead_; | |
| 107 current_environment_->is_dead_ = true; | |
| 108 Environment* next = Copy(current_environment_); | |
| 109 current_environment_->is_dead_ = is_dead; | |
| 110 current_environment_ = next; | |
| 111 } | |
| 112 | |
| 113 | |
| 114 StructuredMachineAssembler::Environment* StructuredMachineAssembler::Copy( | |
| 115 Environment* env, int truncate_at) { | |
| 116 Environment* new_env = new (zone()) Environment(zone(), NULL, env->is_dead_); | |
| 117 if (!new_env->is_dead_) { | |
| 118 new_env->block_ = schedule()->NewBasicBlock(); | |
| 119 } | |
| 120 new_env->variables_.reserve(truncate_at); | |
| 121 NodeVectorIter end = env->variables_.end(); | |
| 122 DCHECK(truncate_at <= static_cast<int>(env->variables_.size())); | |
| 123 end -= static_cast<int>(env->variables_.size()) - truncate_at; | |
| 124 new_env->variables_.insert(new_env->variables_.begin(), | |
| 125 env->variables_.begin(), end); | |
| 126 return new_env; | |
| 127 } | |
| 128 | |
| 129 | |
| 130 StructuredMachineAssembler::Environment* | |
| 131 StructuredMachineAssembler::CopyForLoopHeader(Environment* env) { | |
| 132 Environment* new_env = new (zone()) Environment(zone(), NULL, env->is_dead_); | |
| 133 if (!new_env->is_dead_) { | |
| 134 new_env->block_ = schedule()->NewBasicBlock(); | |
| 135 } | |
| 136 new_env->variables_.reserve(env->variables_.size()); | |
| 137 for (NodeVectorIter i = env->variables_.begin(); i != env->variables_.end(); | |
| 138 ++i) { | |
| 139 Node* phi = NULL; | |
| 140 if (*i != NULL) { | |
| 141 phi = graph()->NewNode(common()->Phi(1), *i); | |
| 142 if (new_env->block_ != NULL) { | |
| 143 schedule()->AddNode(new_env->block_, phi); | |
| 144 } | |
| 145 } | |
| 146 new_env->variables_.push_back(phi); | |
| 147 } | |
| 148 return new_env; | |
| 149 } | |
| 150 | |
| 151 | |
| 152 void StructuredMachineAssembler::MergeBackEdgesToLoopHeader( | |
| 153 Environment* header, EnvironmentVector* environments) { | |
| 154 // Only merge as many variables are were declared before this loop. | |
| 155 int n = static_cast<int>(header->variables_.size()); | |
| 156 // TODO(dcarney): invert loop order and extend phis once. | |
| 157 for (EnvironmentVector::iterator i = environments->begin(); | |
| 158 i != environments->end(); ++i) { | |
| 159 Environment* from = *i; | |
| 160 if (from->is_dead_) continue; | |
| 161 AddGoto(from, header); | |
| 162 for (int i = 0; i < n; ++i) { | |
| 163 Node* phi = header->variables_[i]; | |
| 164 if (phi == NULL) continue; | |
| 165 phi->set_op(common()->Phi(phi->InputCount() + 1)); | |
| 166 phi->AppendInput(zone(), VariableAt(from, i)); | |
| 167 } | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 | |
| 172 void StructuredMachineAssembler::Merge(EnvironmentVector* environments, | |
| 173 int truncate_at) { | |
| 174 DCHECK(current_environment_ == NULL || current_environment_->is_dead_); | |
| 175 Environment* next = new (zone()) Environment(zone(), NULL, false); | |
| 176 current_environment_ = next; | |
| 177 size_t n_vars = number_of_variables_; | |
| 178 NodeVector& vars = next->variables_; | |
| 179 vars.reserve(n_vars); | |
| 180 Node** scratch = NULL; | |
| 181 size_t n_envs = environments->size(); | |
| 182 Environment** live_environments = | |
| 183 zone()->NewArray<Environment*>(static_cast<int>(n_envs)); | |
| 184 size_t n_live = 0; | |
| 185 for (size_t i = 0; i < n_envs; i++) { | |
| 186 if (environments->at(i)->is_dead_) continue; | |
| 187 live_environments[n_live++] = environments->at(i); | |
| 188 } | |
| 189 n_envs = n_live; | |
| 190 if (n_live == 0) next->is_dead_ = true; | |
| 191 if (!next->is_dead_) { | |
| 192 next->block_ = schedule()->NewBasicBlock(); | |
| 193 } | |
| 194 for (size_t j = 0; j < n_vars; ++j) { | |
| 195 Node* resolved = NULL; | |
| 196 // Find first non equal variable. | |
| 197 size_t i = 0; | |
| 198 for (; i < n_envs; i++) { | |
| 199 DCHECK(live_environments[i]->variables_.size() <= n_vars); | |
| 200 Node* val = NULL; | |
| 201 if (j < static_cast<size_t>(truncate_at)) { | |
| 202 val = live_environments[i]->variables_.at(j); | |
| 203 // TODO(dcarney): record start position at time of split. | |
| 204 // all variables after this should not be NULL. | |
| 205 if (val != NULL) { | |
| 206 val = VariableAt(live_environments[i], static_cast<int>(j)); | |
| 207 } | |
| 208 } | |
| 209 if (val == resolved) continue; | |
| 210 if (i != 0) break; | |
| 211 resolved = val; | |
| 212 } | |
| 213 // Have to generate a phi. | |
| 214 if (i < n_envs) { | |
| 215 // All values thus far uninitialized, variable used out of scope. | |
| 216 CHECK(resolved != NULL); | |
| 217 // Init scratch buffer. | |
| 218 if (scratch == NULL) { | |
| 219 scratch = zone()->NewArray<Node*>(static_cast<int>(n_envs)); | |
| 220 } | |
| 221 for (size_t k = 0; k < i; k++) { | |
| 222 scratch[k] = resolved; | |
| 223 } | |
| 224 for (; i < n_envs; i++) { | |
| 225 scratch[i] = live_environments[i]->variables_[j]; | |
| 226 } | |
| 227 resolved = graph()->NewNode(common()->Phi(static_cast<int>(n_envs)), | |
| 228 static_cast<int>(n_envs), scratch); | |
| 229 if (next->block_ != NULL) { | |
| 230 schedule()->AddNode(next->block_, resolved); | |
| 231 } | |
| 232 } | |
| 233 vars.push_back(resolved); | |
| 234 } | |
| 235 } | |
| 236 | |
| 237 | |
| 238 void StructuredMachineAssembler::AddGoto(Environment* from, Environment* to) { | |
| 239 if (to->is_dead_) { | |
| 240 DCHECK(from->is_dead_); | |
| 241 return; | |
| 242 } | |
| 243 DCHECK(!from->is_dead_); | |
| 244 schedule()->AddGoto(from->block_, to->block_); | |
| 245 } | |
| 246 | |
| 247 | |
| 248 // TODO(dcarney): add pass before rpo to schedule to compute these. | |
| 249 BasicBlock* StructuredMachineAssembler::TrampolineFor(BasicBlock* block) { | |
| 250 BasicBlock* trampoline = schedule()->NewBasicBlock(); | |
| 251 schedule()->AddGoto(trampoline, block); | |
| 252 return trampoline; | |
| 253 } | |
| 254 | |
| 255 | |
| 256 void StructuredMachineAssembler::AddBranch(Environment* environment, | |
| 257 Node* condition, | |
| 258 Environment* true_val, | |
| 259 Environment* false_val) { | |
| 260 DCHECK(environment->is_dead_ == true_val->is_dead_); | |
| 261 DCHECK(environment->is_dead_ == false_val->is_dead_); | |
| 262 if (true_val->block_ == false_val->block_) { | |
| 263 if (environment->is_dead_) return; | |
| 264 AddGoto(environment, true_val); | |
| 265 return; | |
| 266 } | |
| 267 Node* branch = graph()->NewNode(common()->Branch(), condition); | |
| 268 if (environment->is_dead_) return; | |
| 269 BasicBlock* true_block = TrampolineFor(true_val->block_); | |
| 270 BasicBlock* false_block = TrampolineFor(false_val->block_); | |
| 271 schedule()->AddBranch(environment->block_, branch, true_block, false_block); | |
| 272 } | |
| 273 | |
| 274 | |
| 275 StructuredMachineAssembler::Environment::Environment(Zone* zone, | |
| 276 BasicBlock* block, | |
| 277 bool is_dead) | |
| 278 : block_(block), variables_(zone), is_dead_(is_dead) {} | |
| 279 | |
| 280 | |
| 281 StructuredMachineAssembler::IfBuilder::IfBuilder( | |
| 282 StructuredMachineAssembler* smasm) | |
| 283 : smasm_(smasm), | |
| 284 if_clauses_(smasm_->zone()), | |
| 285 pending_exit_merges_(smasm_->zone()) { | |
| 286 DCHECK(smasm_->current_environment_ != NULL); | |
| 287 PushNewIfClause(); | |
| 288 DCHECK(!IsDone()); | |
| 289 } | |
| 290 | |
| 291 | |
| 292 StructuredMachineAssembler::IfBuilder& | |
| 293 StructuredMachineAssembler::IfBuilder::If() { | |
| 294 DCHECK(smasm_->current_environment_ != NULL); | |
| 295 IfClause* clause = CurrentClause(); | |
| 296 if (clause->then_environment_ != NULL || clause->else_environment_ != NULL) { | |
| 297 PushNewIfClause(); | |
| 298 } | |
| 299 return *this; | |
| 300 } | |
| 301 | |
| 302 | |
| 303 StructuredMachineAssembler::IfBuilder& | |
| 304 StructuredMachineAssembler::IfBuilder::If(Node* condition) { | |
| 305 If(); | |
| 306 IfClause* clause = CurrentClause(); | |
| 307 // Store branch for future resolution. | |
| 308 UnresolvedBranch* next = new (smasm_->zone()) | |
| 309 UnresolvedBranch(smasm_->current_environment_, condition, NULL); | |
| 310 if (clause->unresolved_list_tail_ != NULL) { | |
| 311 clause->unresolved_list_tail_->next_ = next; | |
| 312 } | |
| 313 clause->unresolved_list_tail_ = next; | |
| 314 // Push onto merge queues. | |
| 315 clause->pending_else_merges_.push_back(next); | |
| 316 clause->pending_then_merges_.push_back(next); | |
| 317 smasm_->current_environment_ = NULL; | |
| 318 return *this; | |
| 319 } | |
| 320 | |
| 321 | |
| 322 void StructuredMachineAssembler::IfBuilder::And() { | |
| 323 CurrentClause()->ResolvePendingMerges(smasm_, kCombineThen, kExpressionTerm); | |
| 324 } | |
| 325 | |
| 326 | |
| 327 void StructuredMachineAssembler::IfBuilder::Or() { | |
| 328 CurrentClause()->ResolvePendingMerges(smasm_, kCombineElse, kExpressionTerm); | |
| 329 } | |
| 330 | |
| 331 | |
| 332 void StructuredMachineAssembler::IfBuilder::Then() { | |
| 333 CurrentClause()->ResolvePendingMerges(smasm_, kCombineThen, kExpressionDone); | |
| 334 } | |
| 335 | |
| 336 | |
| 337 void StructuredMachineAssembler::IfBuilder::Else() { | |
| 338 AddCurrentToPending(); | |
| 339 CurrentClause()->ResolvePendingMerges(smasm_, kCombineElse, kExpressionDone); | |
| 340 } | |
| 341 | |
| 342 | |
| 343 void StructuredMachineAssembler::IfBuilder::AddCurrentToPending() { | |
| 344 if (smasm_->current_environment_ != NULL && | |
| 345 !smasm_->current_environment_->is_dead_) { | |
| 346 pending_exit_merges_.push_back(smasm_->current_environment_); | |
| 347 } | |
| 348 smasm_->current_environment_ = NULL; | |
| 349 } | |
| 350 | |
| 351 | |
| 352 void StructuredMachineAssembler::IfBuilder::PushNewIfClause() { | |
| 353 int curr_size = | |
| 354 static_cast<int>(smasm_->current_environment_->variables_.size()); | |
| 355 IfClause* clause = new (smasm_->zone()) IfClause(smasm_->zone(), curr_size); | |
| 356 if_clauses_.push_back(clause); | |
| 357 } | |
| 358 | |
| 359 | |
| 360 StructuredMachineAssembler::IfBuilder::IfClause::IfClause( | |
| 361 Zone* zone, int initial_environment_size) | |
| 362 : unresolved_list_tail_(NULL), | |
| 363 initial_environment_size_(initial_environment_size), | |
| 364 expression_states_(zone), | |
| 365 pending_then_merges_(zone), | |
| 366 pending_else_merges_(zone), | |
| 367 then_environment_(NULL), | |
| 368 else_environment_(NULL) { | |
| 369 PushNewExpressionState(); | |
| 370 } | |
| 371 | |
| 372 | |
| 373 StructuredMachineAssembler::IfBuilder::PendingMergeStackRange | |
| 374 StructuredMachineAssembler::IfBuilder::IfClause::ComputeRelevantMerges( | |
| 375 CombineType combine_type) { | |
| 376 DCHECK(!expression_states_.empty()); | |
| 377 PendingMergeStack* stack; | |
| 378 int start; | |
| 379 if (combine_type == kCombineThen) { | |
| 380 stack = &pending_then_merges_; | |
| 381 start = expression_states_.back().pending_then_size_; | |
| 382 } else { | |
| 383 DCHECK(combine_type == kCombineElse); | |
| 384 stack = &pending_else_merges_; | |
| 385 start = expression_states_.back().pending_else_size_; | |
| 386 } | |
| 387 PendingMergeStackRange data; | |
| 388 data.merge_stack_ = stack; | |
| 389 data.start_ = start; | |
| 390 data.size_ = static_cast<int>(stack->size()) - start; | |
| 391 return data; | |
| 392 } | |
| 393 | |
| 394 | |
| 395 void StructuredMachineAssembler::IfBuilder::IfClause::ResolvePendingMerges( | |
| 396 StructuredMachineAssembler* smasm, CombineType combine_type, | |
| 397 ResolutionType resolution_type) { | |
| 398 DCHECK(smasm->current_environment_ == NULL); | |
| 399 PendingMergeStackRange data = ComputeRelevantMerges(combine_type); | |
| 400 DCHECK_EQ(data.merge_stack_->back(), unresolved_list_tail_); | |
| 401 DCHECK(data.size_ > 0); | |
| 402 // TODO(dcarney): assert no new variables created during expression building. | |
| 403 int truncate_at = initial_environment_size_; | |
| 404 if (data.size_ == 1) { | |
| 405 // Just copy environment in common case. | |
| 406 smasm->current_environment_ = | |
| 407 smasm->Copy(unresolved_list_tail_->environment_, truncate_at); | |
| 408 } else { | |
| 409 EnvironmentVector environments(smasm->zone()); | |
| 410 environments.reserve(data.size_); | |
| 411 CopyEnvironments(data, &environments); | |
| 412 DCHECK(static_cast<int>(environments.size()) == data.size_); | |
| 413 smasm->Merge(&environments, truncate_at); | |
| 414 } | |
| 415 Environment* then_environment = then_environment_; | |
| 416 Environment* else_environment = NULL; | |
| 417 if (resolution_type == kExpressionDone) { | |
| 418 DCHECK(expression_states_.size() == 1); | |
| 419 // Set the current then_ or else_environment_ to the new merged environment. | |
| 420 if (combine_type == kCombineThen) { | |
| 421 DCHECK(then_environment_ == NULL && else_environment_ == NULL); | |
| 422 this->then_environment_ = smasm->current_environment_; | |
| 423 } else { | |
| 424 DCHECK(else_environment_ == NULL); | |
| 425 this->else_environment_ = smasm->current_environment_; | |
| 426 } | |
| 427 } else { | |
| 428 DCHECK(resolution_type == kExpressionTerm); | |
| 429 DCHECK(then_environment_ == NULL && else_environment_ == NULL); | |
| 430 } | |
| 431 if (combine_type == kCombineThen) { | |
| 432 then_environment = smasm->current_environment_; | |
| 433 } else { | |
| 434 DCHECK(combine_type == kCombineElse); | |
| 435 else_environment = smasm->current_environment_; | |
| 436 } | |
| 437 // Finalize branches and clear the pending stack. | |
| 438 FinalizeBranches(smasm, data, combine_type, then_environment, | |
| 439 else_environment); | |
| 440 } | |
| 441 | |
| 442 | |
| 443 void StructuredMachineAssembler::IfBuilder::IfClause::CopyEnvironments( | |
| 444 const PendingMergeStackRange& data, EnvironmentVector* environments) { | |
| 445 PendingMergeStack::iterator i = data.merge_stack_->begin(); | |
| 446 PendingMergeStack::iterator end = data.merge_stack_->end(); | |
| 447 for (i += data.start_; i != end; ++i) { | |
| 448 environments->push_back((*i)->environment_); | |
| 449 } | |
| 450 } | |
| 451 | |
| 452 | |
| 453 void StructuredMachineAssembler::IfBuilder::IfClause::PushNewExpressionState() { | |
| 454 ExpressionState next; | |
| 455 next.pending_then_size_ = static_cast<int>(pending_then_merges_.size()); | |
| 456 next.pending_else_size_ = static_cast<int>(pending_else_merges_.size()); | |
| 457 expression_states_.push_back(next); | |
| 458 } | |
| 459 | |
| 460 | |
| 461 void StructuredMachineAssembler::IfBuilder::IfClause::PopExpressionState() { | |
| 462 expression_states_.pop_back(); | |
| 463 DCHECK(!expression_states_.empty()); | |
| 464 } | |
| 465 | |
| 466 | |
| 467 void StructuredMachineAssembler::IfBuilder::IfClause::FinalizeBranches( | |
| 468 StructuredMachineAssembler* smasm, const PendingMergeStackRange& data, | |
| 469 CombineType combine_type, Environment* const then_environment, | |
| 470 Environment* const else_environment) { | |
| 471 DCHECK(unresolved_list_tail_ != NULL); | |
| 472 DCHECK(smasm->current_environment_ != NULL); | |
| 473 if (data.size_ == 0) return; | |
| 474 PendingMergeStack::iterator curr = data.merge_stack_->begin(); | |
| 475 PendingMergeStack::iterator end = data.merge_stack_->end(); | |
| 476 // Finalize everything but the head first, | |
| 477 // in the order the branches enter the merge block. | |
| 478 end -= 1; | |
| 479 Environment* true_val = then_environment; | |
| 480 Environment* false_val = else_environment; | |
| 481 Environment** next; | |
| 482 if (combine_type == kCombineThen) { | |
| 483 next = &false_val; | |
| 484 } else { | |
| 485 DCHECK(combine_type == kCombineElse); | |
| 486 next = &true_val; | |
| 487 } | |
| 488 for (curr += data.start_; curr != end; ++curr) { | |
| 489 UnresolvedBranch* branch = *curr; | |
| 490 *next = branch->next_->environment_; | |
| 491 smasm->AddBranch(branch->environment_, branch->condition_, true_val, | |
| 492 false_val); | |
| 493 } | |
| 494 DCHECK(curr + 1 == data.merge_stack_->end()); | |
| 495 // Now finalize the tail if possible. | |
| 496 if (then_environment != NULL && else_environment != NULL) { | |
| 497 UnresolvedBranch* branch = *curr; | |
| 498 smasm->AddBranch(branch->environment_, branch->condition_, then_environment, | |
| 499 else_environment); | |
| 500 } | |
| 501 // Clear the merge stack. | |
| 502 PendingMergeStack::iterator begin = data.merge_stack_->begin(); | |
| 503 begin += data.start_; | |
| 504 data.merge_stack_->erase(begin, data.merge_stack_->end()); | |
| 505 DCHECK_EQ(static_cast<int>(data.merge_stack_->size()), data.start_); | |
| 506 } | |
| 507 | |
| 508 | |
| 509 void StructuredMachineAssembler::IfBuilder::End() { | |
| 510 DCHECK(!IsDone()); | |
| 511 AddCurrentToPending(); | |
| 512 size_t current_pending = pending_exit_merges_.size(); | |
| 513 // All unresolved branch edges are now set to pending. | |
| 514 for (IfClauses::iterator i = if_clauses_.begin(); i != if_clauses_.end(); | |
| 515 ++i) { | |
| 516 IfClause* clause = *i; | |
| 517 DCHECK(clause->expression_states_.size() == 1); | |
| 518 PendingMergeStackRange data; | |
| 519 // Copy then environments. | |
| 520 data = clause->ComputeRelevantMerges(kCombineThen); | |
| 521 clause->CopyEnvironments(data, &pending_exit_merges_); | |
| 522 Environment* head = NULL; | |
| 523 // Will resolve the head node in the else_merge | |
| 524 if (data.size_ > 0 && clause->then_environment_ == NULL && | |
| 525 clause->else_environment_ == NULL) { | |
| 526 head = pending_exit_merges_.back(); | |
| 527 pending_exit_merges_.pop_back(); | |
| 528 } | |
| 529 // Copy else environments. | |
| 530 data = clause->ComputeRelevantMerges(kCombineElse); | |
| 531 clause->CopyEnvironments(data, &pending_exit_merges_); | |
| 532 if (head != NULL) { | |
| 533 // Must have data to merge, or else head will never get a branch. | |
| 534 DCHECK(data.size_ != 0); | |
| 535 pending_exit_merges_.push_back(head); | |
| 536 } | |
| 537 } | |
| 538 smasm_->Merge(&pending_exit_merges_, | |
| 539 if_clauses_[0]->initial_environment_size_); | |
| 540 // Anything initally pending jumps into the new environment. | |
| 541 for (size_t i = 0; i < current_pending; ++i) { | |
| 542 smasm_->AddGoto(pending_exit_merges_[i], smasm_->current_environment_); | |
| 543 } | |
| 544 // Resolve all branches. | |
| 545 for (IfClauses::iterator i = if_clauses_.begin(); i != if_clauses_.end(); | |
| 546 ++i) { | |
| 547 IfClause* clause = *i; | |
| 548 // Must finalize all environments, so ensure they are set correctly. | |
| 549 Environment* then_environment = clause->then_environment_; | |
| 550 if (then_environment == NULL) { | |
| 551 then_environment = smasm_->current_environment_; | |
| 552 } | |
| 553 Environment* else_environment = clause->else_environment_; | |
| 554 PendingMergeStackRange data; | |
| 555 // Finalize then environments. | |
| 556 data = clause->ComputeRelevantMerges(kCombineThen); | |
| 557 clause->FinalizeBranches(smasm_, data, kCombineThen, then_environment, | |
| 558 else_environment); | |
| 559 // Finalize else environments. | |
| 560 // Now set the else environment so head is finalized for edge case above. | |
| 561 if (else_environment == NULL) { | |
| 562 else_environment = smasm_->current_environment_; | |
| 563 } | |
| 564 data = clause->ComputeRelevantMerges(kCombineElse); | |
| 565 clause->FinalizeBranches(smasm_, data, kCombineElse, then_environment, | |
| 566 else_environment); | |
| 567 } | |
| 568 // Future accesses to this builder should crash immediately. | |
| 569 pending_exit_merges_.clear(); | |
| 570 if_clauses_.clear(); | |
| 571 DCHECK(IsDone()); | |
| 572 } | |
| 573 | |
| 574 | |
| 575 StructuredMachineAssembler::LoopBuilder::LoopBuilder( | |
| 576 StructuredMachineAssembler* smasm) | |
| 577 : smasm_(smasm), | |
| 578 header_environment_(NULL), | |
| 579 pending_header_merges_(smasm_->zone()), | |
| 580 pending_exit_merges_(smasm_->zone()) { | |
| 581 DCHECK(smasm_->current_environment_ != NULL); | |
| 582 // Create header environment. | |
| 583 header_environment_ = smasm_->CopyForLoopHeader(smasm_->current_environment_); | |
| 584 smasm_->AddGoto(smasm_->current_environment_, header_environment_); | |
| 585 // Create body environment. | |
| 586 Environment* body = smasm_->Copy(header_environment_); | |
| 587 smasm_->AddGoto(header_environment_, body); | |
| 588 smasm_->current_environment_ = body; | |
| 589 DCHECK(!IsDone()); | |
| 590 } | |
| 591 | |
| 592 | |
| 593 void StructuredMachineAssembler::LoopBuilder::Continue() { | |
| 594 DCHECK(!IsDone()); | |
| 595 pending_header_merges_.push_back(smasm_->current_environment_); | |
| 596 smasm_->CopyCurrentAsDead(); | |
| 597 } | |
| 598 | |
| 599 | |
| 600 void StructuredMachineAssembler::LoopBuilder::Break() { | |
| 601 DCHECK(!IsDone()); | |
| 602 pending_exit_merges_.push_back(smasm_->current_environment_); | |
| 603 smasm_->CopyCurrentAsDead(); | |
| 604 } | |
| 605 | |
| 606 | |
| 607 void StructuredMachineAssembler::LoopBuilder::End() { | |
| 608 DCHECK(!IsDone()); | |
| 609 if (smasm_->current_environment_ != NULL) { | |
| 610 Continue(); | |
| 611 } | |
| 612 // Do loop header merges. | |
| 613 smasm_->MergeBackEdgesToLoopHeader(header_environment_, | |
| 614 &pending_header_merges_); | |
| 615 int initial_size = static_cast<int>(header_environment_->variables_.size()); | |
| 616 // Do loop exit merges, truncating loop variables away. | |
| 617 smasm_->Merge(&pending_exit_merges_, initial_size); | |
| 618 for (EnvironmentVector::iterator i = pending_exit_merges_.begin(); | |
| 619 i != pending_exit_merges_.end(); ++i) { | |
| 620 smasm_->AddGoto(*i, smasm_->current_environment_); | |
| 621 } | |
| 622 pending_header_merges_.clear(); | |
| 623 pending_exit_merges_.clear(); | |
| 624 header_environment_ = NULL; | |
| 625 DCHECK(IsDone()); | |
| 626 } | |
| 627 | |
| 628 } // namespace compiler | |
| 629 } // namespace internal | |
| 630 } // namespace v8 | |
| OLD | NEW |