| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 end_(NULL), | 58 end_(NULL), |
| 59 loop_information_(NULL), | 59 loop_information_(NULL), |
| 60 predecessors_(2), | 60 predecessors_(2), |
| 61 dominator_(NULL), | 61 dominator_(NULL), |
| 62 dominated_blocks_(4), | 62 dominated_blocks_(4), |
| 63 last_environment_(NULL), | 63 last_environment_(NULL), |
| 64 argument_count_(-1), | 64 argument_count_(-1), |
| 65 first_instruction_index_(-1), | 65 first_instruction_index_(-1), |
| 66 last_instruction_index_(-1), | 66 last_instruction_index_(-1), |
| 67 deleted_phis_(4), | 67 deleted_phis_(4), |
| 68 parent_loop_header_(NULL), |
| 68 is_inline_return_target_(false) { | 69 is_inline_return_target_(false) { |
| 69 } | 70 } |
| 70 | 71 |
| 71 | 72 |
| 72 void HBasicBlock::AttachLoopInformation() { | 73 void HBasicBlock::AttachLoopInformation() { |
| 73 ASSERT(!IsLoopHeader()); | 74 ASSERT(!IsLoopHeader()); |
| 74 loop_information_ = new HLoopInformation(this); | 75 loop_information_ = new HLoopInformation(this); |
| 75 } | 76 } |
| 76 | 77 |
| 77 | 78 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 98 } | 99 } |
| 99 | 100 |
| 100 | 101 |
| 101 void HBasicBlock::AddInstruction(HInstruction* instr) { | 102 void HBasicBlock::AddInstruction(HInstruction* instr) { |
| 102 ASSERT(!IsStartBlock() || !IsFinished()); | 103 ASSERT(!IsStartBlock() || !IsFinished()); |
| 103 ASSERT(!instr->IsLinked()); | 104 ASSERT(!instr->IsLinked()); |
| 104 ASSERT(!IsFinished()); | 105 ASSERT(!IsFinished()); |
| 105 if (first_ == NULL) { | 106 if (first_ == NULL) { |
| 106 HBlockEntry* entry = new HBlockEntry(); | 107 HBlockEntry* entry = new HBlockEntry(); |
| 107 entry->InitializeAsFirst(this); | 108 entry->InitializeAsFirst(this); |
| 108 first_ = entry; | 109 first_ = last_ = entry; |
| 109 } | 110 } |
| 110 instr->InsertAfter(GetLastInstruction()); | 111 instr->InsertAfter(last_); |
| 111 } | 112 last_ = instr; |
| 112 | |
| 113 | |
| 114 HInstruction* HBasicBlock::GetLastInstruction() { | |
| 115 if (end_ != NULL) return end_->previous(); | |
| 116 if (first_ == NULL) return NULL; | |
| 117 if (last_ == NULL) last_ = first_; | |
| 118 while (last_->next() != NULL) last_ = last_->next(); | |
| 119 return last_; | |
| 120 } | 113 } |
| 121 | 114 |
| 122 | 115 |
| 123 HSimulate* HBasicBlock::CreateSimulate(int id) { | 116 HSimulate* HBasicBlock::CreateSimulate(int id) { |
| 124 ASSERT(HasEnvironment()); | 117 ASSERT(HasEnvironment()); |
| 125 HEnvironment* environment = last_environment(); | 118 HEnvironment* environment = last_environment(); |
| 126 ASSERT(id == AstNode::kNoNumber || | 119 ASSERT(id == AstNode::kNoNumber || |
| 127 environment->closure()->shared()->VerifyBailoutId(id)); | 120 environment->closure()->shared()->VerifyBailoutId(id)); |
| 128 | 121 |
| 129 int push_count = environment->push_count(); | 122 int push_count = environment->push_count(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 UpdateEnvironment(env); | 163 UpdateEnvironment(env); |
| 171 } | 164 } |
| 172 | 165 |
| 173 | 166 |
| 174 void HBasicBlock::SetJoinId(int id) { | 167 void HBasicBlock::SetJoinId(int id) { |
| 175 int length = predecessors_.length(); | 168 int length = predecessors_.length(); |
| 176 ASSERT(length > 0); | 169 ASSERT(length > 0); |
| 177 for (int i = 0; i < length; i++) { | 170 for (int i = 0; i < length; i++) { |
| 178 HBasicBlock* predecessor = predecessors_[i]; | 171 HBasicBlock* predecessor = predecessors_[i]; |
| 179 ASSERT(predecessor->end()->IsGoto()); | 172 ASSERT(predecessor->end()->IsGoto()); |
| 180 HSimulate* simulate = HSimulate::cast(predecessor->GetLastInstruction()); | 173 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); |
| 181 // We only need to verify the ID once. | 174 // We only need to verify the ID once. |
| 182 ASSERT(i != 0 || | 175 ASSERT(i != 0 || |
| 183 predecessor->last_environment()->closure()->shared() | 176 predecessor->last_environment()->closure()->shared() |
| 184 ->VerifyBailoutId(id)); | 177 ->VerifyBailoutId(id)); |
| 185 simulate->set_ast_id(id); | 178 simulate->set_ast_id(id); |
| 186 } | 179 } |
| 187 } | 180 } |
| 188 | 181 |
| 189 | 182 |
| 190 bool HBasicBlock::Dominates(HBasicBlock* other) const { | 183 bool HBasicBlock::Dominates(HBasicBlock* other) const { |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 286 UNREACHABLE(); | 279 UNREACHABLE(); |
| 287 return -1; | 280 return -1; |
| 288 } | 281 } |
| 289 | 282 |
| 290 | 283 |
| 291 #ifdef DEBUG | 284 #ifdef DEBUG |
| 292 void HBasicBlock::Verify() { | 285 void HBasicBlock::Verify() { |
| 293 // Check that every block is finished. | 286 // Check that every block is finished. |
| 294 ASSERT(IsFinished()); | 287 ASSERT(IsFinished()); |
| 295 ASSERT(block_id() >= 0); | 288 ASSERT(block_id() >= 0); |
| 296 | |
| 297 // Verify that all blocks targetting a branch target, have the same boolean | |
| 298 // value on top of their expression stack. | |
| 299 if (!cond().is_null()) { | |
| 300 ASSERT(predecessors()->length() > 0); | |
| 301 for (int i = 1; i < predecessors()->length(); i++) { | |
| 302 HBasicBlock* pred = predecessors()->at(i); | |
| 303 HValue* top = pred->last_environment()->Top(); | |
| 304 ASSERT(top->IsConstant()); | |
| 305 Object* a = *HConstant::cast(top)->handle(); | |
| 306 Object* b = *cond(); | |
| 307 ASSERT(a == b); | |
| 308 } | |
| 309 } | |
| 310 } | 289 } |
| 311 #endif | 290 #endif |
| 312 | 291 |
| 313 | 292 |
| 314 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) { | 293 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) { |
| 315 this->back_edges_.Add(block); | 294 this->back_edges_.Add(block); |
| 316 AddBlock(block); | 295 AddBlock(block); |
| 317 } | 296 } |
| 318 | 297 |
| 319 | 298 |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 496 HConstant* HGraph::GetConstantTrue() { | 475 HConstant* HGraph::GetConstantTrue() { |
| 497 return GetConstant(&constant_true_, HEAP->true_value()); | 476 return GetConstant(&constant_true_, HEAP->true_value()); |
| 498 } | 477 } |
| 499 | 478 |
| 500 | 479 |
| 501 HConstant* HGraph::GetConstantFalse() { | 480 HConstant* HGraph::GetConstantFalse() { |
| 502 return GetConstant(&constant_false_, HEAP->false_value()); | 481 return GetConstant(&constant_false_, HEAP->false_value()); |
| 503 } | 482 } |
| 504 | 483 |
| 505 | 484 |
| 506 void HSubgraph::AppendOptional(HSubgraph* graph, | 485 HBasicBlock* HGraphBuilder::CreateJoin(HBasicBlock* first, |
| 507 bool on_true_branch, | 486 HBasicBlock* second, |
| 508 HValue* value) { | 487 int join_id) { |
| 509 ASSERT(HasExit() && graph->HasExit()); | 488 if (first == NULL) { |
| 510 HBasicBlock* other_block = graph_->CreateBasicBlock(); | 489 return second; |
| 511 HBasicBlock* join_block = graph_->CreateBasicBlock(); | 490 } else if (second == NULL) { |
| 512 | 491 return first; |
| 513 HTest* test = on_true_branch | 492 } else { |
| 514 ? new HTest(value, graph->entry_block(), other_block) | |
| 515 : new HTest(value, other_block, graph->entry_block()); | |
| 516 exit_block_->Finish(test); | |
| 517 other_block->Goto(join_block); | |
| 518 graph->exit_block()->Goto(join_block); | |
| 519 exit_block_ = join_block; | |
| 520 } | |
| 521 | |
| 522 | |
| 523 void HSubgraph::AppendJoin(HSubgraph* then_graph, | |
| 524 HSubgraph* else_graph, | |
| 525 AstNode* node) { | |
| 526 if (then_graph->HasExit() && else_graph->HasExit()) { | |
| 527 // We need to merge, create new merge block. | |
| 528 HBasicBlock* join_block = graph_->CreateBasicBlock(); | 493 HBasicBlock* join_block = graph_->CreateBasicBlock(); |
| 529 then_graph->exit_block()->Goto(join_block); | 494 first->Goto(join_block); |
| 530 else_graph->exit_block()->Goto(join_block); | 495 second->Goto(join_block); |
| 531 join_block->SetJoinId(node->id()); | 496 join_block->SetJoinId(join_id); |
| 532 exit_block_ = join_block; | 497 return join_block; |
| 533 } else if (then_graph->HasExit()) { | |
| 534 exit_block_ = then_graph->exit_block_; | |
| 535 } else if (else_graph->HasExit()) { | |
| 536 exit_block_ = else_graph->exit_block_; | |
| 537 } else { | |
| 538 exit_block_ = NULL; | |
| 539 } | 498 } |
| 540 } | 499 } |
| 541 | 500 |
| 542 | 501 |
| 543 void HSubgraph::ResolveContinue(IterationStatement* statement) { | 502 HBasicBlock* HGraphBuilder::JoinContinue(IterationStatement* statement, |
| 544 HBasicBlock* continue_block = BundleContinue(statement); | 503 HBasicBlock* exit_block, |
| 504 HBasicBlock* continue_block) { |
| 545 if (continue_block != NULL) { | 505 if (continue_block != NULL) { |
| 546 exit_block_ = JoinBlocks(exit_block(), | 506 if (exit_block != NULL) exit_block->Goto(continue_block); |
| 547 continue_block, | 507 continue_block->SetJoinId(statement->ContinueId()); |
| 548 statement->ContinueId()); | 508 return continue_block; |
| 549 } | 509 } |
| 510 return exit_block; |
| 550 } | 511 } |
| 551 | 512 |
| 552 | 513 |
| 553 HBasicBlock* HSubgraph::BundleBreak(BreakableStatement* statement) { | 514 HBasicBlock* HGraphBuilder::CreateLoop(IterationStatement* statement, |
| 554 return BundleBreakContinue(statement, false, statement->ExitId()); | 515 HBasicBlock* loop_entry, |
| 516 HBasicBlock* body_exit, |
| 517 HBasicBlock* loop_successor, |
| 518 HBasicBlock* break_block) { |
| 519 if (body_exit != NULL) body_exit->Goto(loop_entry, true); |
| 520 loop_entry->PostProcessLoopHeader(statement); |
| 521 if (break_block != NULL) { |
| 522 if (loop_successor != NULL) loop_successor->Goto(break_block); |
| 523 break_block->SetJoinId(statement->ExitId()); |
| 524 return break_block; |
| 525 } |
| 526 return loop_successor; |
| 555 } | 527 } |
| 556 | 528 |
| 557 | 529 |
| 558 HBasicBlock* HSubgraph::BundleContinue(IterationStatement* statement) { | 530 void HBasicBlock::FinishExit(HControlInstruction* instruction) { |
| 559 return BundleBreakContinue(statement, true, statement->ContinueId()); | 531 Finish(instruction); |
| 560 } | 532 ClearEnvironment(); |
| 561 | |
| 562 | |
| 563 HBasicBlock* HSubgraph::BundleBreakContinue(BreakableStatement* statement, | |
| 564 bool is_continue, | |
| 565 int join_id) { | |
| 566 HBasicBlock* result = NULL; | |
| 567 const ZoneList<BreakContinueInfo*>* infos = break_continue_info(); | |
| 568 for (int i = 0; i < infos->length(); ++i) { | |
| 569 BreakContinueInfo* info = infos->at(i); | |
| 570 if (info->is_continue() == is_continue && | |
| 571 info->target() == statement && | |
| 572 !info->IsResolved()) { | |
| 573 if (result == NULL) { | |
| 574 result = graph_->CreateBasicBlock(); | |
| 575 } | |
| 576 info->block()->Goto(result); | |
| 577 info->Resolve(); | |
| 578 } | |
| 579 } | |
| 580 | |
| 581 if (result != NULL) result->SetJoinId(join_id); | |
| 582 | |
| 583 return result; | |
| 584 } | |
| 585 | |
| 586 | |
| 587 HBasicBlock* HSubgraph::JoinBlocks(HBasicBlock* a, HBasicBlock* b, int id) { | |
| 588 if (a == NULL) return b; | |
| 589 if (b == NULL) return a; | |
| 590 HBasicBlock* target = graph_->CreateBasicBlock(); | |
| 591 a->Goto(target); | |
| 592 b->Goto(target); | |
| 593 target->SetJoinId(id); | |
| 594 return target; | |
| 595 } | |
| 596 | |
| 597 | |
| 598 void HSubgraph::AppendEndless(HSubgraph* body, IterationStatement* statement) { | |
| 599 ConnectExitTo(body->entry_block()); | |
| 600 body->ResolveContinue(statement); | |
| 601 body->ConnectExitTo(body->entry_block(), true); | |
| 602 exit_block_ = body->BundleBreak(statement); | |
| 603 body->entry_block()->PostProcessLoopHeader(statement); | |
| 604 } | |
| 605 | |
| 606 | |
| 607 void HSubgraph::AppendDoWhile(HSubgraph* body, | |
| 608 IterationStatement* statement, | |
| 609 HSubgraph* go_back, | |
| 610 HSubgraph* exit) { | |
| 611 ConnectExitTo(body->entry_block()); | |
| 612 go_back->ConnectExitTo(body->entry_block(), true); | |
| 613 | |
| 614 HBasicBlock* break_block = body->BundleBreak(statement); | |
| 615 exit_block_ = | |
| 616 JoinBlocks(exit->exit_block(), break_block, statement->ExitId()); | |
| 617 body->entry_block()->PostProcessLoopHeader(statement); | |
| 618 } | |
| 619 | |
| 620 | |
| 621 void HSubgraph::AppendWhile(HSubgraph* condition, | |
| 622 HSubgraph* body, | |
| 623 IterationStatement* statement, | |
| 624 HSubgraph* continue_subgraph, | |
| 625 HSubgraph* exit) { | |
| 626 ConnectExitTo(condition->entry_block()); | |
| 627 | |
| 628 HBasicBlock* break_block = body->BundleBreak(statement); | |
| 629 exit_block_ = | |
| 630 JoinBlocks(exit->exit_block(), break_block, statement->ExitId()); | |
| 631 | |
| 632 if (continue_subgraph != NULL) { | |
| 633 body->ConnectExitTo(continue_subgraph->entry_block(), true); | |
| 634 continue_subgraph->entry_block()->SetJoinId(statement->EntryId()); | |
| 635 exit_block_ = JoinBlocks(exit_block_, | |
| 636 continue_subgraph->exit_block(), | |
| 637 statement->ExitId()); | |
| 638 } else { | |
| 639 body->ConnectExitTo(condition->entry_block(), true); | |
| 640 } | |
| 641 condition->entry_block()->PostProcessLoopHeader(statement); | |
| 642 } | |
| 643 | |
| 644 | |
| 645 void HSubgraph::Append(HSubgraph* next, BreakableStatement* stmt) { | |
| 646 exit_block_->Goto(next->entry_block()); | |
| 647 exit_block_ = next->exit_block_; | |
| 648 | |
| 649 if (stmt != NULL) { | |
| 650 next->entry_block()->SetJoinId(stmt->EntryId()); | |
| 651 HBasicBlock* break_block = next->BundleBreak(stmt); | |
| 652 exit_block_ = JoinBlocks(exit_block(), break_block, stmt->ExitId()); | |
| 653 } | |
| 654 } | |
| 655 | |
| 656 | |
| 657 void HSubgraph::FinishExit(HControlInstruction* instruction) { | |
| 658 ASSERT(HasExit()); | |
| 659 exit_block_->Finish(instruction); | |
| 660 exit_block_->ClearEnvironment(); | |
| 661 exit_block_ = NULL; | |
| 662 } | |
| 663 | |
| 664 | |
| 665 void HSubgraph::FinishBreakContinue(BreakableStatement* target, | |
| 666 bool is_continue) { | |
| 667 ASSERT(!exit_block_->IsFinished()); | |
| 668 BreakContinueInfo* info = new BreakContinueInfo(target, exit_block_, | |
| 669 is_continue); | |
| 670 break_continue_info_.Add(info); | |
| 671 exit_block_ = NULL; | |
| 672 } | 533 } |
| 673 | 534 |
| 674 | 535 |
| 675 HGraph::HGraph(CompilationInfo* info) | 536 HGraph::HGraph(CompilationInfo* info) |
| 676 : HSubgraph(this), | 537 : HSubgraph(this), |
| 677 next_block_id_(0), | 538 next_block_id_(0), |
| 678 info_(info), | 539 info_(info), |
| 679 blocks_(8), | 540 blocks_(8), |
| 680 values_(16), | 541 values_(16), |
| 681 phi_list_(NULL) { | 542 phi_list_(NULL) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 732 | 593 |
| 733 | 594 |
| 734 HBasicBlock* HGraph::CreateBasicBlock() { | 595 HBasicBlock* HGraph::CreateBasicBlock() { |
| 735 HBasicBlock* result = new HBasicBlock(this); | 596 HBasicBlock* result = new HBasicBlock(this); |
| 736 blocks_.Add(result); | 597 blocks_.Add(result); |
| 737 return result; | 598 return result; |
| 738 } | 599 } |
| 739 | 600 |
| 740 | 601 |
| 741 void HGraph::Canonicalize() { | 602 void HGraph::Canonicalize() { |
| 603 if (!FLAG_use_canonicalizing) return; |
| 742 HPhase phase("Canonicalize", this); | 604 HPhase phase("Canonicalize", this); |
| 743 if (FLAG_use_canonicalizing) { | 605 for (int i = 0; i < blocks()->length(); ++i) { |
| 744 for (int i = 0; i < blocks()->length(); ++i) { | 606 HInstruction* instr = blocks()->at(i)->first(); |
| 745 HBasicBlock* b = blocks()->at(i); | 607 while (instr != NULL) { |
| 746 for (HInstruction* insn = b->first(); insn != NULL; insn = insn->next()) { | 608 HValue* value = instr->Canonicalize(); |
| 747 HValue* value = insn->Canonicalize(); | 609 if (value != instr) instr->ReplaceAndDelete(value); |
| 748 if (value != insn) { | 610 instr = instr->next(); |
| 749 if (value != NULL) { | |
| 750 insn->ReplaceAndDelete(value); | |
| 751 } else { | |
| 752 insn->Delete(); | |
| 753 } | |
| 754 } | |
| 755 } | |
| 756 } | 611 } |
| 757 } | 612 } |
| 758 } | 613 } |
| 759 | 614 |
| 760 | 615 |
| 761 void HGraph::OrderBlocks() { | 616 void HGraph::OrderBlocks() { |
| 762 HPhase phase("Block ordering"); | 617 HPhase phase("Block ordering"); |
| 763 BitVector visited(blocks_.length()); | 618 BitVector visited(blocks_.length()); |
| 764 | 619 |
| 765 ZoneList<HBasicBlock*> reverse_result(8); | 620 ZoneList<HBasicBlock*> reverse_result(8); |
| (...skipping 735 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1501 TraceGVN("Instruction %d kills\n", instr->id()); | 1356 TraceGVN("Instruction %d kills\n", instr->id()); |
| 1502 } else if (instr->CheckFlag(HValue::kUseGVN)) { | 1357 } else if (instr->CheckFlag(HValue::kUseGVN)) { |
| 1503 HValue* other = map->Lookup(instr); | 1358 HValue* other = map->Lookup(instr); |
| 1504 if (other != NULL) { | 1359 if (other != NULL) { |
| 1505 ASSERT(instr->Equals(other) && other->Equals(instr)); | 1360 ASSERT(instr->Equals(other) && other->Equals(instr)); |
| 1506 TraceGVN("Replacing value %d (%s) with value %d (%s)\n", | 1361 TraceGVN("Replacing value %d (%s) with value %d (%s)\n", |
| 1507 instr->id(), | 1362 instr->id(), |
| 1508 instr->Mnemonic(), | 1363 instr->Mnemonic(), |
| 1509 other->id(), | 1364 other->id(), |
| 1510 other->Mnemonic()); | 1365 other->Mnemonic()); |
| 1511 instr->ReplaceValue(other); | 1366 instr->ReplaceAndDelete(other); |
| 1512 instr->Delete(); | |
| 1513 } else { | 1367 } else { |
| 1514 map->Add(instr); | 1368 map->Add(instr); |
| 1515 } | 1369 } |
| 1516 } | 1370 } |
| 1517 instr = next; | 1371 instr = next; |
| 1518 } | 1372 } |
| 1519 | 1373 |
| 1520 // Recursively continue analysis for all immediately dominated blocks. | 1374 // Recursively continue analysis for all immediately dominated blocks. |
| 1521 int length = block->dominated_blocks()->length(); | 1375 int length = block->dominated_blocks()->length(); |
| 1522 for (int i = 0; i < length; ++i) { | 1376 for (int i = 0; i < length; ++i) { |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1806 } | 1660 } |
| 1807 } | 1661 } |
| 1808 | 1662 |
| 1809 | 1663 |
| 1810 void HGraph::InsertRepresentationChangeForUse(HValue* value, | 1664 void HGraph::InsertRepresentationChangeForUse(HValue* value, |
| 1811 HValue* use, | 1665 HValue* use, |
| 1812 Representation to, | 1666 Representation to, |
| 1813 bool is_truncating) { | 1667 bool is_truncating) { |
| 1814 // Insert the representation change right before its use. For phi-uses we | 1668 // Insert the representation change right before its use. For phi-uses we |
| 1815 // insert at the end of the corresponding predecessor. | 1669 // insert at the end of the corresponding predecessor. |
| 1816 HBasicBlock* insert_block = use->block(); | 1670 HInstruction* next = NULL; |
| 1817 if (use->IsPhi()) { | 1671 if (use->IsPhi()) { |
| 1818 int index = 0; | 1672 int index = 0; |
| 1819 while (use->OperandAt(index) != value) ++index; | 1673 while (use->OperandAt(index) != value) ++index; |
| 1820 insert_block = insert_block->predecessors()->at(index); | 1674 next = use->block()->predecessors()->at(index)->end(); |
| 1675 } else { |
| 1676 next = HInstruction::cast(use); |
| 1821 } | 1677 } |
| 1822 | 1678 |
| 1823 HInstruction* next = (insert_block == use->block()) | |
| 1824 ? HInstruction::cast(use) | |
| 1825 : insert_block->end(); | |
| 1826 | |
| 1827 // For constants we try to make the representation change at compile | 1679 // For constants we try to make the representation change at compile |
| 1828 // time. When a representation change is not possible without loss of | 1680 // time. When a representation change is not possible without loss of |
| 1829 // information we treat constants like normal instructions and insert the | 1681 // information we treat constants like normal instructions and insert the |
| 1830 // change instructions for them. | 1682 // change instructions for them. |
| 1831 HInstruction* new_value = NULL; | 1683 HInstruction* new_value = NULL; |
| 1832 if (value->IsConstant()) { | 1684 if (value->IsConstant()) { |
| 1833 HConstant* constant = HConstant::cast(value); | 1685 HConstant* constant = HConstant::cast(value); |
| 1834 // Try to create a new copy of the constant with the new representation. | 1686 // Try to create a new copy of the constant with the new representation. |
| 1835 new_value = is_truncating | 1687 new_value = is_truncating |
| 1836 ? constant->CopyToTruncatedInt32() | 1688 ? constant->CopyToTruncatedInt32() |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2008 } | 1860 } |
| 2009 | 1861 |
| 2010 | 1862 |
| 2011 AstContext::~AstContext() { | 1863 AstContext::~AstContext() { |
| 2012 owner_->set_ast_context(outer_); // Pop. | 1864 owner_->set_ast_context(outer_); // Pop. |
| 2013 } | 1865 } |
| 2014 | 1866 |
| 2015 | 1867 |
| 2016 EffectContext::~EffectContext() { | 1868 EffectContext::~EffectContext() { |
| 2017 ASSERT(owner()->HasStackOverflow() || | 1869 ASSERT(owner()->HasStackOverflow() || |
| 2018 !owner()->subgraph()->HasExit() || | 1870 owner()->current_block() == NULL || |
| 2019 owner()->environment()->length() == original_length_); | 1871 owner()->environment()->length() == original_length_); |
| 2020 } | 1872 } |
| 2021 | 1873 |
| 2022 | 1874 |
| 2023 ValueContext::~ValueContext() { | 1875 ValueContext::~ValueContext() { |
| 2024 ASSERT(owner()->HasStackOverflow() || | 1876 ASSERT(owner()->HasStackOverflow() || |
| 2025 !owner()->subgraph()->HasExit() || | 1877 owner()->current_block() == NULL || |
| 2026 owner()->environment()->length() == original_length_ + 1); | 1878 owner()->environment()->length() == original_length_ + 1); |
| 2027 } | 1879 } |
| 2028 | 1880 |
| 2029 | 1881 |
| 2030 void EffectContext::ReturnValue(HValue* value) { | 1882 void EffectContext::ReturnValue(HValue* value) { |
| 2031 // The value is simply ignored. | 1883 // The value is simply ignored. |
| 2032 } | 1884 } |
| 2033 | 1885 |
| 2034 | 1886 |
| 2035 void ValueContext::ReturnValue(HValue* value) { | 1887 void ValueContext::ReturnValue(HValue* value) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2073 | 1925 |
| 2074 void TestContext::BuildBranch(HValue* value) { | 1926 void TestContext::BuildBranch(HValue* value) { |
| 2075 // We expect the graph to be in edge-split form: there is no edge that | 1927 // We expect the graph to be in edge-split form: there is no edge that |
| 2076 // connects a branch node to a join node. We conservatively ensure that | 1928 // connects a branch node to a join node. We conservatively ensure that |
| 2077 // property by always adding an empty block on the outgoing edges of this | 1929 // property by always adding an empty block on the outgoing edges of this |
| 2078 // branch. | 1930 // branch. |
| 2079 HGraphBuilder* builder = owner(); | 1931 HGraphBuilder* builder = owner(); |
| 2080 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); | 1932 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
| 2081 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); | 1933 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
| 2082 HTest* test = new HTest(value, empty_true, empty_false); | 1934 HTest* test = new HTest(value, empty_true, empty_false); |
| 2083 builder->CurrentBlock()->Finish(test); | 1935 builder->current_block()->Finish(test); |
| 2084 | 1936 |
| 2085 HValue* const no_return_value = NULL; | 1937 HValue* const no_return_value = NULL; |
| 2086 HBasicBlock* true_target = if_true(); | 1938 HBasicBlock* true_target = if_true(); |
| 2087 if (true_target->IsInlineReturnTarget()) { | 1939 if (true_target->IsInlineReturnTarget()) { |
| 2088 empty_true->AddLeaveInlined(no_return_value, true_target); | 1940 empty_true->AddLeaveInlined(no_return_value, true_target); |
| 2089 } else { | 1941 } else { |
| 2090 empty_true->Goto(true_target); | 1942 empty_true->Goto(true_target); |
| 2091 } | 1943 } |
| 2092 | 1944 |
| 2093 HBasicBlock* false_target = if_false(); | 1945 HBasicBlock* false_target = if_false(); |
| 2094 if (false_target->IsInlineReturnTarget()) { | 1946 if (false_target->IsInlineReturnTarget()) { |
| 2095 empty_false->AddLeaveInlined(no_return_value, false_target); | 1947 empty_false->AddLeaveInlined(no_return_value, false_target); |
| 2096 } else { | 1948 } else { |
| 2097 empty_false->Goto(false_target); | 1949 empty_false->Goto(false_target); |
| 2098 } | 1950 } |
| 2099 builder->subgraph()->set_exit_block(NULL); | 1951 builder->set_current_block(NULL); |
| 2100 } | 1952 } |
| 2101 | 1953 |
| 2102 | 1954 |
| 2103 // HGraphBuilder infrastructure for bailing out and checking bailouts. | 1955 // HGraphBuilder infrastructure for bailing out and checking bailouts. |
| 2104 #define BAILOUT(reason) \ | 1956 #define BAILOUT(reason) \ |
| 2105 do { \ | 1957 do { \ |
| 2106 Bailout(reason); \ | 1958 Bailout(reason); \ |
| 2107 return; \ | 1959 return; \ |
| 2108 } while (false) | 1960 } while (false) |
| 2109 | 1961 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2146 class HGraphBuilder::SubgraphScope BASE_EMBEDDED { | 1998 class HGraphBuilder::SubgraphScope BASE_EMBEDDED { |
| 2147 public: | 1999 public: |
| 2148 SubgraphScope(HGraphBuilder* builder, HSubgraph* new_subgraph) | 2000 SubgraphScope(HGraphBuilder* builder, HSubgraph* new_subgraph) |
| 2149 : builder_(builder) { | 2001 : builder_(builder) { |
| 2150 old_subgraph_ = builder_->current_subgraph_; | 2002 old_subgraph_ = builder_->current_subgraph_; |
| 2151 subgraph_ = new_subgraph; | 2003 subgraph_ = new_subgraph; |
| 2152 builder_->current_subgraph_ = subgraph_; | 2004 builder_->current_subgraph_ = subgraph_; |
| 2153 } | 2005 } |
| 2154 | 2006 |
| 2155 ~SubgraphScope() { | 2007 ~SubgraphScope() { |
| 2156 old_subgraph_->AddBreakContinueInfo(subgraph_); | |
| 2157 builder_->current_subgraph_ = old_subgraph_; | 2008 builder_->current_subgraph_ = old_subgraph_; |
| 2158 } | 2009 } |
| 2159 | 2010 |
| 2160 HSubgraph* subgraph() const { return subgraph_; } | 2011 HSubgraph* subgraph() const { return subgraph_; } |
| 2161 | 2012 |
| 2162 private: | 2013 private: |
| 2163 HGraphBuilder* builder_; | 2014 HGraphBuilder* builder_; |
| 2164 HSubgraph* old_subgraph_; | 2015 HSubgraph* old_subgraph_; |
| 2165 HSubgraph* subgraph_; | 2016 HSubgraph* subgraph_; |
| 2166 }; | 2017 }; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2188 | 2039 |
| 2189 | 2040 |
| 2190 void HGraphBuilder::VisitForControl(Expression* expr, | 2041 void HGraphBuilder::VisitForControl(Expression* expr, |
| 2191 HBasicBlock* true_block, | 2042 HBasicBlock* true_block, |
| 2192 HBasicBlock* false_block) { | 2043 HBasicBlock* false_block) { |
| 2193 TestContext for_test(this, true_block, false_block); | 2044 TestContext for_test(this, true_block, false_block); |
| 2194 Visit(expr); | 2045 Visit(expr); |
| 2195 } | 2046 } |
| 2196 | 2047 |
| 2197 | 2048 |
| 2198 HValue* HGraphBuilder::VisitArgument(Expression* expr) { | 2049 void HGraphBuilder::VisitArgument(Expression* expr) { |
| 2199 VisitForValue(expr); | 2050 VISIT_FOR_VALUE(expr); |
| 2200 if (HasStackOverflow() || !subgraph()->HasExit()) return NULL; | 2051 Push(AddInstruction(new HPushArgument(Pop()))); |
| 2201 return environment()->Top(); | |
| 2202 } | 2052 } |
| 2203 | 2053 |
| 2204 | 2054 |
| 2205 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { | 2055 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { |
| 2206 for (int i = 0; i < arguments->length(); i++) { | 2056 for (int i = 0; i < arguments->length(); i++) { |
| 2207 VisitArgument(arguments->at(i)); | 2057 VisitArgument(arguments->at(i)); |
| 2208 if (HasStackOverflow() || !current_subgraph_->HasExit()) return; | 2058 if (HasStackOverflow() || current_block() == NULL) return; |
| 2059 } |
| 2060 } |
| 2061 |
| 2062 |
| 2063 void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) { |
| 2064 for (int i = 0; i < exprs->length(); ++i) { |
| 2065 VISIT_FOR_VALUE(exprs->at(i)); |
| 2209 } | 2066 } |
| 2210 } | 2067 } |
| 2211 | 2068 |
| 2212 | 2069 |
| 2213 HGraph* HGraphBuilder::CreateGraph(CompilationInfo* info) { | 2070 HGraph* HGraphBuilder::CreateGraph(CompilationInfo* info) { |
| 2214 ASSERT(current_subgraph_ == NULL); | 2071 ASSERT(subgraph() == NULL); |
| 2215 graph_ = new HGraph(info); | 2072 graph_ = new HGraph(info); |
| 2216 | 2073 |
| 2217 { | 2074 { |
| 2218 HPhase phase("Block building"); | 2075 HPhase phase("Block building"); |
| 2219 graph_->Initialize(CreateBasicBlock(graph_->start_environment())); | 2076 graph()->Initialize(CreateBasicBlock(graph()->start_environment())); |
| 2220 current_subgraph_ = graph_; | 2077 current_subgraph_ = graph(); |
| 2221 | 2078 |
| 2222 Scope* scope = info->scope(); | 2079 Scope* scope = info->scope(); |
| 2080 if (scope->HasIllegalRedeclaration()) { |
| 2081 Bailout("function with illegal redeclaration"); |
| 2082 return NULL; |
| 2083 } |
| 2223 SetupScope(scope); | 2084 SetupScope(scope); |
| 2224 VisitDeclarations(scope->declarations()); | 2085 VisitDeclarations(scope->declarations()); |
| 2225 | |
| 2226 AddInstruction(new HStackCheck()); | 2086 AddInstruction(new HStackCheck()); |
| 2227 | 2087 |
| 2228 ZoneList<Statement*>* stmts = info->function()->body(); | 2088 // Add an edge to the body entry. This is warty: the graph's start |
| 2229 HSubgraph* body = CreateGotoSubgraph(environment()); | 2089 // environment will be used by the Lithium translation as the initial |
| 2230 AddToSubgraph(body, stmts); | 2090 // environment on graph entry, but it has now been mutated by the |
| 2091 // Hydrogen translation of the instructions in the start block. This |
| 2092 // environment uses values which have not been defined yet. These |
| 2093 // Hydrogen instructions will then be replayed by the Lithium |
| 2094 // translation, so they cannot have an environment effect. The edge to |
| 2095 // the body's entry block (along with some special logic for the start |
| 2096 // block in HInstruction::InsertAfter) seals the start block from |
| 2097 // getting unwanted instructions inserted. |
| 2098 // |
| 2099 // TODO(kmillikin): Fix this. Stop mutating the initial environment. |
| 2100 // Make the Hydrogen instructions in the initial block into Hydrogen |
| 2101 // values (but not instructions), present in the initial environment and |
| 2102 // not replayed by the Lithium translation. |
| 2103 HEnvironment* initial_env = environment()->CopyWithoutHistory(); |
| 2104 HBasicBlock* body_entry = CreateBasicBlock(initial_env); |
| 2105 current_block()->Goto(body_entry); |
| 2106 body_entry->SetJoinId(info->function()->id()); |
| 2107 set_current_block(body_entry); |
| 2108 VisitStatements(info->function()->body()); |
| 2231 if (HasStackOverflow()) return NULL; | 2109 if (HasStackOverflow()) return NULL; |
| 2232 current_subgraph_->Append(body, NULL); | |
| 2233 body->entry_block()->SetJoinId(info->function()->id()); | |
| 2234 | 2110 |
| 2235 if (graph_->HasExit()) { | 2111 if (current_block() != NULL) { |
| 2236 graph_->FinishExit(new HReturn(graph_->GetConstantUndefined())); | 2112 HReturn* instr = new HReturn(graph()->GetConstantUndefined()); |
| 2113 current_block()->FinishExit(instr); |
| 2114 set_current_block(NULL); |
| 2237 } | 2115 } |
| 2238 } | 2116 } |
| 2239 | 2117 |
| 2240 graph_->OrderBlocks(); | 2118 graph()->OrderBlocks(); |
| 2241 graph_->AssignDominators(); | 2119 graph()->AssignDominators(); |
| 2242 graph_->EliminateRedundantPhis(); | 2120 graph()->EliminateRedundantPhis(); |
| 2243 if (!graph_->CollectPhis()) { | 2121 if (!graph()->CollectPhis()) { |
| 2244 Bailout("Phi-use of arguments object"); | 2122 Bailout("Phi-use of arguments object"); |
| 2245 return NULL; | 2123 return NULL; |
| 2246 } | 2124 } |
| 2247 | 2125 |
| 2248 HInferRepresentation rep(graph_); | 2126 HInferRepresentation rep(graph()); |
| 2249 rep.Analyze(); | 2127 rep.Analyze(); |
| 2250 | 2128 |
| 2251 if (FLAG_use_range) { | 2129 if (FLAG_use_range) { |
| 2252 HRangeAnalysis rangeAnalysis(graph_); | 2130 HRangeAnalysis rangeAnalysis(graph()); |
| 2253 rangeAnalysis.Analyze(); | 2131 rangeAnalysis.Analyze(); |
| 2254 } | 2132 } |
| 2255 | 2133 |
| 2256 graph_->InitializeInferredTypes(); | 2134 graph()->InitializeInferredTypes(); |
| 2257 graph_->Canonicalize(); | 2135 graph()->Canonicalize(); |
| 2258 graph_->InsertRepresentationChanges(); | 2136 graph()->InsertRepresentationChanges(); |
| 2259 graph_->ComputeMinusZeroChecks(); | 2137 graph()->ComputeMinusZeroChecks(); |
| 2260 | 2138 |
| 2261 // Eliminate redundant stack checks on backwards branches. | 2139 // Eliminate redundant stack checks on backwards branches. |
| 2262 HStackCheckEliminator sce(graph_); | 2140 HStackCheckEliminator sce(graph()); |
| 2263 sce.Process(); | 2141 sce.Process(); |
| 2264 | 2142 |
| 2265 // Perform common subexpression elimination and loop-invariant code motion. | 2143 // Perform common subexpression elimination and loop-invariant code motion. |
| 2266 if (FLAG_use_gvn) { | 2144 if (FLAG_use_gvn) { |
| 2267 HPhase phase("Global value numbering", graph_); | 2145 HPhase phase("Global value numbering", graph()); |
| 2268 HGlobalValueNumberer gvn(graph_); | 2146 HGlobalValueNumberer gvn(graph()); |
| 2269 gvn.Analyze(); | 2147 gvn.Analyze(); |
| 2270 } | 2148 } |
| 2271 | 2149 |
| 2272 return graph_; | 2150 return graph(); |
| 2273 } | 2151 } |
| 2274 | 2152 |
| 2275 | 2153 |
| 2276 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Statement* stmt) { | 2154 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Statement* stmt) { |
| 2277 SubgraphScope scope(this, graph); | 2155 SubgraphScope scope(this, graph); |
| 2278 Visit(stmt); | 2156 Visit(stmt); |
| 2279 } | 2157 } |
| 2280 | 2158 |
| 2281 | 2159 |
| 2282 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Expression* expr) { | 2160 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Expression* expr) { |
| 2283 SubgraphScope scope(this, graph); | 2161 SubgraphScope scope(this, graph); |
| 2284 VisitForValue(expr); | 2162 VisitForValue(expr); |
| 2285 } | 2163 } |
| 2286 | 2164 |
| 2287 | 2165 |
| 2288 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, | 2166 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, |
| 2289 ZoneList<Statement*>* stmts) { | 2167 ZoneList<Statement*>* stmts) { |
| 2290 SubgraphScope scope(this, graph); | 2168 SubgraphScope scope(this, graph); |
| 2291 VisitStatements(stmts); | 2169 VisitStatements(stmts); |
| 2292 } | 2170 } |
| 2293 | 2171 |
| 2294 | 2172 |
| 2295 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { | 2173 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { |
| 2296 ASSERT(current_subgraph_->HasExit()); | 2174 ASSERT(current_block() != NULL); |
| 2297 current_subgraph_->exit_block()->AddInstruction(instr); | 2175 current_block()->AddInstruction(instr); |
| 2298 return instr; | 2176 return instr; |
| 2299 } | 2177 } |
| 2300 | 2178 |
| 2301 | 2179 |
| 2302 void HGraphBuilder::AddSimulate(int id) { | 2180 void HGraphBuilder::AddSimulate(int id) { |
| 2303 ASSERT(current_subgraph_->HasExit()); | 2181 ASSERT(current_block() != NULL); |
| 2304 current_subgraph_->exit_block()->AddSimulate(id); | 2182 current_block()->AddSimulate(id); |
| 2305 } | 2183 } |
| 2306 | 2184 |
| 2307 | 2185 |
| 2308 void HGraphBuilder::AddPhi(HPhi* instr) { | 2186 void HGraphBuilder::AddPhi(HPhi* instr) { |
| 2309 ASSERT(current_subgraph_->HasExit()); | 2187 ASSERT(current_block() != NULL); |
| 2310 current_subgraph_->exit_block()->AddPhi(instr); | 2188 current_block()->AddPhi(instr); |
| 2311 } | 2189 } |
| 2312 | 2190 |
| 2313 | 2191 |
| 2314 void HGraphBuilder::PushAndAdd(HInstruction* instr) { | 2192 void HGraphBuilder::PushAndAdd(HInstruction* instr) { |
| 2315 Push(instr); | 2193 Push(instr); |
| 2316 AddInstruction(instr); | 2194 AddInstruction(instr); |
| 2317 } | 2195 } |
| 2318 | 2196 |
| 2319 | 2197 |
| 2320 void HGraphBuilder::PushArgumentsForStubCall(int argument_count) { | 2198 template <int V> |
| 2321 const int kMaxStubArguments = 4; | 2199 HInstruction* HGraphBuilder::PreProcessCall(HCall<V>* call) { |
| 2322 ASSERT_GE(kMaxStubArguments, argument_count); | 2200 int count = call->argument_count(); |
| 2323 // Push the arguments on the stack. | 2201 ZoneList<HValue*> arguments(count); |
| 2324 HValue* arguments[kMaxStubArguments]; | 2202 for (int i = 0; i < count; ++i) { |
| 2325 for (int i = argument_count - 1; i >= 0; i--) { | 2203 arguments.Add(Pop()); |
| 2326 arguments[i] = Pop(); | |
| 2327 } | 2204 } |
| 2328 for (int i = 0; i < argument_count; i++) { | 2205 |
| 2329 AddInstruction(new HPushArgument(arguments[i])); | 2206 while (!arguments.is_empty()) { |
| 2207 AddInstruction(new HPushArgument(arguments.RemoveLast())); |
| 2330 } | 2208 } |
| 2209 return call; |
| 2331 } | 2210 } |
| 2332 | 2211 |
| 2333 | 2212 |
| 2334 void HGraphBuilder::ProcessCall(HCall* call) { | |
| 2335 for (int i = call->argument_count() - 1; i >= 0; --i) { | |
| 2336 HValue* value = Pop(); | |
| 2337 HPushArgument* push = new HPushArgument(value); | |
| 2338 call->SetArgumentAt(i, push); | |
| 2339 } | |
| 2340 | |
| 2341 for (int i = 0; i < call->argument_count(); ++i) { | |
| 2342 AddInstruction(call->PushArgumentAt(i)); | |
| 2343 } | |
| 2344 } | |
| 2345 | |
| 2346 | |
| 2347 void HGraphBuilder::SetupScope(Scope* scope) { | 2213 void HGraphBuilder::SetupScope(Scope* scope) { |
| 2348 // We don't yet handle the function name for named function expressions. | 2214 // We don't yet handle the function name for named function expressions. |
| 2349 if (scope->function() != NULL) BAILOUT("named function expression"); | 2215 if (scope->function() != NULL) BAILOUT("named function expression"); |
| 2350 | 2216 |
| 2351 // We can't handle heap-allocated locals. | |
| 2352 if (scope->num_heap_slots() > 0) BAILOUT("heap allocated locals"); | |
| 2353 | |
| 2354 HConstant* undefined_constant = | 2217 HConstant* undefined_constant = |
| 2355 new HConstant(FACTORY->undefined_value(), Representation::Tagged()); | 2218 new HConstant(FACTORY->undefined_value(), Representation::Tagged()); |
| 2356 AddInstruction(undefined_constant); | 2219 AddInstruction(undefined_constant); |
| 2357 graph_->set_undefined_constant(undefined_constant); | 2220 graph_->set_undefined_constant(undefined_constant); |
| 2358 | 2221 |
| 2359 // Set the initial values of parameters including "this". "This" has | 2222 // Set the initial values of parameters including "this". "This" has |
| 2360 // parameter index 0. | 2223 // parameter index 0. |
| 2361 int count = scope->num_parameters() + 1; | 2224 int count = scope->num_parameters() + 1; |
| 2362 for (int i = 0; i < count; ++i) { | 2225 for (int i = 0; i < count; ++i) { |
| 2363 HInstruction* parameter = AddInstruction(new HParameter(i)); | 2226 HInstruction* parameter = AddInstruction(new HParameter(i)); |
| 2364 environment()->Bind(i, parameter); | 2227 environment()->Bind(i, parameter); |
| 2365 } | 2228 } |
| 2366 | 2229 |
| 2367 // Set the initial values of stack-allocated locals. | 2230 // Set the initial values of stack-allocated locals. |
| 2368 for (int i = count; i < environment()->length(); ++i) { | 2231 for (int i = count; i < environment()->length(); ++i) { |
| 2369 environment()->Bind(i, undefined_constant); | 2232 environment()->Bind(i, undefined_constant); |
| 2370 } | 2233 } |
| 2371 | 2234 |
| 2372 // Handle the arguments and arguments shadow variables specially (they do | 2235 // Handle the arguments and arguments shadow variables specially (they do |
| 2373 // not have declarations). | 2236 // not have declarations). |
| 2374 if (scope->arguments() != NULL) { | 2237 if (scope->arguments() != NULL) { |
| 2238 if (!scope->arguments()->IsStackAllocated() || |
| 2239 !scope->arguments_shadow()->IsStackAllocated()) { |
| 2240 BAILOUT("context-allocated arguments"); |
| 2241 } |
| 2375 HArgumentsObject* object = new HArgumentsObject; | 2242 HArgumentsObject* object = new HArgumentsObject; |
| 2376 AddInstruction(object); | 2243 AddInstruction(object); |
| 2377 graph()->SetArgumentsObject(object); | 2244 graph()->SetArgumentsObject(object); |
| 2378 environment()->Bind(scope->arguments(), object); | 2245 environment()->Bind(scope->arguments(), object); |
| 2379 environment()->Bind(scope->arguments_shadow(), object); | 2246 environment()->Bind(scope->arguments_shadow(), object); |
| 2380 } | 2247 } |
| 2381 } | 2248 } |
| 2382 | 2249 |
| 2383 | 2250 |
| 2384 void HGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) { | 2251 void HGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) { |
| 2385 for (int i = 0; i < statements->length(); i++) { | 2252 for (int i = 0; i < statements->length(); i++) { |
| 2386 Visit(statements->at(i)); | 2253 Visit(statements->at(i)); |
| 2387 if (HasStackOverflow() || !current_subgraph_->HasExit()) break; | 2254 if (HasStackOverflow() || current_block() == NULL) break; |
| 2388 } | 2255 } |
| 2389 } | 2256 } |
| 2390 | 2257 |
| 2391 | 2258 |
| 2392 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { | 2259 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { |
| 2393 HBasicBlock* b = graph()->CreateBasicBlock(); | 2260 HBasicBlock* b = graph()->CreateBasicBlock(); |
| 2394 b->SetInitialEnvironment(env); | 2261 b->SetInitialEnvironment(env); |
| 2395 return b; | 2262 return b; |
| 2396 } | 2263 } |
| 2397 | 2264 |
| 2398 | 2265 |
| 2399 HSubgraph* HGraphBuilder::CreateInlinedSubgraph(HEnvironment* outer, | 2266 HSubgraph* HGraphBuilder::CreateInlinedSubgraph(HEnvironment* outer, |
| 2400 Handle<JSFunction> target, | 2267 Handle<JSFunction> target, |
| 2401 FunctionLiteral* function) { | 2268 FunctionLiteral* function) { |
| 2402 HConstant* undefined = graph()->GetConstantUndefined(); | 2269 HConstant* undefined = graph()->GetConstantUndefined(); |
| 2403 HEnvironment* inner = | 2270 HEnvironment* inner = |
| 2404 outer->CopyForInlining(target, function, true, undefined); | 2271 outer->CopyForInlining(target, function, true, undefined); |
| 2405 HSubgraph* subgraph = new HSubgraph(graph()); | 2272 HSubgraph* subgraph = new HSubgraph(graph()); |
| 2406 subgraph->Initialize(CreateBasicBlock(inner)); | 2273 subgraph->Initialize(CreateBasicBlock(inner)); |
| 2407 return subgraph; | 2274 return subgraph; |
| 2408 } | 2275 } |
| 2409 | 2276 |
| 2410 | 2277 |
| 2411 HSubgraph* HGraphBuilder::CreateGotoSubgraph(HEnvironment* env) { | |
| 2412 HSubgraph* subgraph = new HSubgraph(graph()); | |
| 2413 HEnvironment* new_env = env->CopyWithoutHistory(); | |
| 2414 subgraph->Initialize(CreateBasicBlock(new_env)); | |
| 2415 return subgraph; | |
| 2416 } | |
| 2417 | |
| 2418 | |
| 2419 HSubgraph* HGraphBuilder::CreateEmptySubgraph() { | 2278 HSubgraph* HGraphBuilder::CreateEmptySubgraph() { |
| 2420 HSubgraph* subgraph = new HSubgraph(graph()); | 2279 HSubgraph* subgraph = new HSubgraph(graph()); |
| 2421 subgraph->Initialize(graph()->CreateBasicBlock()); | 2280 subgraph->Initialize(graph()->CreateBasicBlock()); |
| 2422 return subgraph; | 2281 return subgraph; |
| 2423 } | 2282 } |
| 2424 | 2283 |
| 2425 | 2284 |
| 2426 HSubgraph* HGraphBuilder::CreateBranchSubgraph(HEnvironment* env) { | 2285 HSubgraph* HGraphBuilder::CreateBranchSubgraph(HEnvironment* env) { |
| 2427 HSubgraph* subgraph = new HSubgraph(graph()); | 2286 HSubgraph* subgraph = new HSubgraph(graph()); |
| 2428 HEnvironment* new_env = env->Copy(); | 2287 HEnvironment* new_env = env->Copy(); |
| 2429 subgraph->Initialize(CreateBasicBlock(new_env)); | 2288 subgraph->Initialize(CreateBasicBlock(new_env)); |
| 2430 return subgraph; | 2289 return subgraph; |
| 2431 } | 2290 } |
| 2432 | 2291 |
| 2433 | 2292 |
| 2434 HSubgraph* HGraphBuilder::CreateLoopHeaderSubgraph(HEnvironment* env) { | 2293 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { |
| 2435 HSubgraph* subgraph = new HSubgraph(graph()); | 2294 HBasicBlock* header = graph()->CreateBasicBlock(); |
| 2436 HBasicBlock* block = graph()->CreateBasicBlock(); | 2295 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); |
| 2437 HEnvironment* new_env = env->CopyAsLoopHeader(block); | 2296 header->SetInitialEnvironment(entry_env); |
| 2438 block->SetInitialEnvironment(new_env); | 2297 header->AttachLoopInformation(); |
| 2439 subgraph->Initialize(block); | 2298 return header; |
| 2440 subgraph->entry_block()->AttachLoopInformation(); | |
| 2441 return subgraph; | |
| 2442 } | 2299 } |
| 2443 | 2300 |
| 2444 | 2301 |
| 2445 void HGraphBuilder::VisitBlock(Block* stmt) { | 2302 void HGraphBuilder::VisitBlock(Block* stmt) { |
| 2446 if (stmt->labels() != NULL) { | 2303 BreakAndContinueInfo break_info(stmt); |
| 2447 HSubgraph* block_graph = CreateGotoSubgraph(environment()); | 2304 { BreakAndContinueScope push(&break_info, this); |
| 2448 ADD_TO_SUBGRAPH(block_graph, stmt->statements()); | |
| 2449 current_subgraph_->Append(block_graph, stmt); | |
| 2450 } else { | |
| 2451 VisitStatements(stmt->statements()); | 2305 VisitStatements(stmt->statements()); |
| 2306 CHECK_BAILOUT; |
| 2307 } |
| 2308 HBasicBlock* break_block = break_info.break_block(); |
| 2309 if (break_block != NULL) { |
| 2310 if (current_block() != NULL) current_block()->Goto(break_block); |
| 2311 break_block->SetJoinId(stmt->ExitId()); |
| 2312 set_current_block(break_block); |
| 2452 } | 2313 } |
| 2453 } | 2314 } |
| 2454 | 2315 |
| 2455 | 2316 |
| 2456 void HGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) { | 2317 void HGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) { |
| 2457 VisitForEffect(stmt->expression()); | 2318 VisitForEffect(stmt->expression()); |
| 2458 } | 2319 } |
| 2459 | 2320 |
| 2460 | 2321 |
| 2461 void HGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { | 2322 void HGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { |
| 2462 } | 2323 } |
| 2463 | 2324 |
| 2464 | 2325 |
| 2465 void HGraphBuilder::VisitIfStatement(IfStatement* stmt) { | 2326 void HGraphBuilder::VisitIfStatement(IfStatement* stmt) { |
| 2466 if (stmt->condition()->ToBooleanIsTrue()) { | 2327 if (stmt->condition()->ToBooleanIsTrue()) { |
| 2467 AddSimulate(stmt->ThenId()); | 2328 AddSimulate(stmt->ThenId()); |
| 2468 Visit(stmt->then_statement()); | 2329 Visit(stmt->then_statement()); |
| 2469 } else if (stmt->condition()->ToBooleanIsFalse()) { | 2330 } else if (stmt->condition()->ToBooleanIsFalse()) { |
| 2470 AddSimulate(stmt->ElseId()); | 2331 AddSimulate(stmt->ElseId()); |
| 2471 Visit(stmt->else_statement()); | 2332 Visit(stmt->else_statement()); |
| 2472 } else { | 2333 } else { |
| 2473 HSubgraph* then_graph = CreateEmptySubgraph(); | 2334 HBasicBlock* cond_true = graph()->CreateBasicBlock(); |
| 2474 HSubgraph* else_graph = CreateEmptySubgraph(); | 2335 HBasicBlock* cond_false = graph()->CreateBasicBlock(); |
| 2475 VISIT_FOR_CONTROL(stmt->condition(), | 2336 VISIT_FOR_CONTROL(stmt->condition(), cond_true, cond_false); |
| 2476 then_graph->entry_block(), | 2337 cond_true->SetJoinId(stmt->ThenId()); |
| 2477 else_graph->entry_block()); | 2338 cond_false->SetJoinId(stmt->ElseId()); |
| 2478 | 2339 |
| 2479 then_graph->entry_block()->SetJoinId(stmt->ThenId()); | 2340 set_current_block(cond_true); |
| 2480 ADD_TO_SUBGRAPH(then_graph, stmt->then_statement()); | 2341 Visit(stmt->then_statement()); |
| 2342 CHECK_BAILOUT; |
| 2343 HBasicBlock* other = current_block(); |
| 2481 | 2344 |
| 2482 else_graph->entry_block()->SetJoinId(stmt->ElseId()); | 2345 set_current_block(cond_false); |
| 2483 ADD_TO_SUBGRAPH(else_graph, stmt->else_statement()); | 2346 Visit(stmt->else_statement()); |
| 2347 CHECK_BAILOUT; |
| 2484 | 2348 |
| 2485 current_subgraph_->AppendJoin(then_graph, else_graph, stmt); | 2349 HBasicBlock* join = CreateJoin(other, current_block(), stmt->id()); |
| 2350 set_current_block(join); |
| 2486 } | 2351 } |
| 2487 } | 2352 } |
| 2488 | 2353 |
| 2489 | 2354 |
| 2355 HBasicBlock* HGraphBuilder::BreakAndContinueScope::Get( |
| 2356 BreakableStatement* stmt, |
| 2357 BreakType type) { |
| 2358 BreakAndContinueScope* current = this; |
| 2359 while (current != NULL && current->info()->target() != stmt) { |
| 2360 current = current->next(); |
| 2361 } |
| 2362 ASSERT(current != NULL); // Always found (unless stack is malformed). |
| 2363 HBasicBlock* block = NULL; |
| 2364 switch (type) { |
| 2365 case BREAK: |
| 2366 block = current->info()->break_block(); |
| 2367 if (block == NULL) { |
| 2368 block = current->owner()->graph()->CreateBasicBlock(); |
| 2369 current->info()->set_break_block(block); |
| 2370 } |
| 2371 break; |
| 2372 |
| 2373 case CONTINUE: |
| 2374 block = current->info()->continue_block(); |
| 2375 if (block == NULL) { |
| 2376 block = current->owner()->graph()->CreateBasicBlock(); |
| 2377 current->info()->set_continue_block(block); |
| 2378 } |
| 2379 break; |
| 2380 } |
| 2381 |
| 2382 return block; |
| 2383 } |
| 2384 |
| 2385 |
| 2490 void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { | 2386 void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { |
| 2491 current_subgraph_->FinishBreakContinue(stmt->target(), true); | 2387 HBasicBlock* continue_block = break_scope()->Get(stmt->target(), CONTINUE); |
| 2388 current_block()->Goto(continue_block); |
| 2389 set_current_block(NULL); |
| 2492 } | 2390 } |
| 2493 | 2391 |
| 2494 | 2392 |
| 2495 void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { | 2393 void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { |
| 2496 current_subgraph_->FinishBreakContinue(stmt->target(), false); | 2394 HBasicBlock* break_block = break_scope()->Get(stmt->target(), BREAK); |
| 2395 current_block()->Goto(break_block); |
| 2396 set_current_block(NULL); |
| 2497 } | 2397 } |
| 2498 | 2398 |
| 2499 | 2399 |
| 2500 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { | 2400 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
| 2501 AstContext* context = call_context(); | 2401 AstContext* context = call_context(); |
| 2502 if (context == NULL) { | 2402 if (context == NULL) { |
| 2503 // Not an inlined return, so an actual one. | 2403 // Not an inlined return, so an actual one. |
| 2504 VISIT_FOR_VALUE(stmt->expression()); | 2404 VISIT_FOR_VALUE(stmt->expression()); |
| 2505 HValue* result = environment()->Pop(); | 2405 HValue* result = environment()->Pop(); |
| 2506 subgraph()->FinishExit(new HReturn(result)); | 2406 current_block()->FinishExit(new HReturn(result)); |
| 2407 set_current_block(NULL); |
| 2507 } else { | 2408 } else { |
| 2508 // Return from an inlined function, visit the subexpression in the | 2409 // Return from an inlined function, visit the subexpression in the |
| 2509 // expression context of the call. | 2410 // expression context of the call. |
| 2510 if (context->IsTest()) { | 2411 if (context->IsTest()) { |
| 2511 TestContext* test = TestContext::cast(context); | 2412 TestContext* test = TestContext::cast(context); |
| 2512 VisitForControl(stmt->expression(), | 2413 VisitForControl(stmt->expression(), |
| 2513 test->if_true(), | 2414 test->if_true(), |
| 2514 test->if_false()); | 2415 test->if_false()); |
| 2515 } else { | 2416 } else { |
| 2516 HValue* return_value = NULL; | 2417 HValue* return_value = NULL; |
| 2517 if (context->IsEffect()) { | 2418 if (context->IsEffect()) { |
| 2518 VISIT_FOR_EFFECT(stmt->expression()); | 2419 VISIT_FOR_EFFECT(stmt->expression()); |
| 2519 return_value = graph()->GetConstantUndefined(); | 2420 return_value = graph()->GetConstantUndefined(); |
| 2520 } else { | 2421 } else { |
| 2521 ASSERT(context->IsValue()); | 2422 ASSERT(context->IsValue()); |
| 2522 VISIT_FOR_VALUE(stmt->expression()); | 2423 VISIT_FOR_VALUE(stmt->expression()); |
| 2523 return_value = environment()->Pop(); | 2424 return_value = environment()->Pop(); |
| 2524 } | 2425 } |
| 2525 subgraph()->exit_block()->AddLeaveInlined(return_value, | 2426 current_block()->AddLeaveInlined(return_value, |
| 2526 function_return_); | 2427 function_return_); |
| 2527 subgraph()->set_exit_block(NULL); | 2428 set_current_block(NULL); |
| 2528 } | 2429 } |
| 2529 } | 2430 } |
| 2530 } | 2431 } |
| 2531 | 2432 |
| 2532 | 2433 |
| 2533 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { | 2434 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { |
| 2534 BAILOUT("WithEnterStatement"); | 2435 BAILOUT("WithEnterStatement"); |
| 2535 } | 2436 } |
| 2536 | 2437 |
| 2537 | 2438 |
| 2538 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) { | 2439 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) { |
| 2539 BAILOUT("WithExitStatement"); | 2440 BAILOUT("WithExitStatement"); |
| 2540 } | 2441 } |
| 2541 | 2442 |
| 2542 | 2443 |
| 2543 HCompare* HGraphBuilder::BuildSwitchCompare(HSubgraph* subgraph, | 2444 HCompare* HGraphBuilder::BuildSwitchCompare(HSubgraph* subgraph, |
| 2544 HValue* switch_value, | 2445 HValue* switch_value, |
| 2545 CaseClause* clause) { | 2446 CaseClause* clause) { |
| 2546 AddToSubgraph(subgraph, clause->label()); | 2447 AddToSubgraph(subgraph, clause->label()); |
| 2547 if (HasStackOverflow()) return NULL; | 2448 if (HasStackOverflow()) return NULL; |
| 2548 HValue* clause_value = subgraph->environment()->Pop(); | 2449 HValue* clause_value = subgraph->exit_block()->last_environment()->Pop(); |
| 2549 HCompare* compare = new HCompare(switch_value, | 2450 HCompare* compare = new HCompare(switch_value, |
| 2550 clause_value, | 2451 clause_value, |
| 2551 Token::EQ_STRICT); | 2452 Token::EQ_STRICT); |
| 2552 compare->SetInputRepresentation(Representation::Integer32()); | 2453 compare->SetInputRepresentation(Representation::Integer32()); |
| 2553 subgraph->exit_block()->AddInstruction(compare); | 2454 subgraph->exit_block()->AddInstruction(compare); |
| 2554 return compare; | 2455 return compare; |
| 2555 } | 2456 } |
| 2556 | 2457 |
| 2557 | 2458 |
| 2558 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 2459 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2619 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); | 2520 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); |
| 2620 if (HasStackOverflow()) return; | 2521 if (HasStackOverflow()) return; |
| 2621 | 2522 |
| 2622 prev_graph = subgraph; | 2523 prev_graph = subgraph; |
| 2623 } | 2524 } |
| 2624 | 2525 |
| 2625 // Finish last comparison if there was at least one comparison. | 2526 // Finish last comparison if there was at least one comparison. |
| 2626 // last_false_block is the (empty) false-block of the last comparison. If | 2527 // last_false_block is the (empty) false-block of the last comparison. If |
| 2627 // there are no comparisons at all (a single default clause), it is just | 2528 // there are no comparisons at all (a single default clause), it is just |
| 2628 // the last block of the current subgraph. | 2529 // the last block of the current subgraph. |
| 2629 HBasicBlock* last_false_block = current_subgraph_->exit_block(); | 2530 HBasicBlock* last_false_block = current_block(); |
| 2630 if (prev_graph != current_subgraph_) { | 2531 if (prev_graph != current_subgraph_) { |
| 2631 last_false_block = graph()->CreateBasicBlock(); | 2532 last_false_block = graph()->CreateBasicBlock(); |
| 2632 HBasicBlock* empty = graph()->CreateBasicBlock(); | 2533 HBasicBlock* empty = graph()->CreateBasicBlock(); |
| 2633 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst, | 2534 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst, |
| 2634 empty, | 2535 empty, |
| 2635 last_false_block)); | 2536 last_false_block)); |
| 2636 } | 2537 } |
| 2637 | 2538 |
| 2638 // If we have a non-smi compare clause, we deoptimize after trying | 2539 // If we have a non-smi compare clause, we deoptimize after trying |
| 2639 // all the previous compares. | 2540 // all the previous compares. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2662 ASSERT(clause->IsSmiCompare()); | 2563 ASSERT(clause->IsSmiCompare()); |
| 2663 // Connect with the corresponding comparison. | 2564 // Connect with the corresponding comparison. |
| 2664 subgraph = CreateEmptySubgraph(); | 2565 subgraph = CreateEmptySubgraph(); |
| 2665 HBasicBlock* empty = | 2566 HBasicBlock* empty = |
| 2666 compare_graphs.at(i)->exit_block()->end()->FirstSuccessor(); | 2567 compare_graphs.at(i)->exit_block()->end()->FirstSuccessor(); |
| 2667 empty->Finish(new HGoto(subgraph->entry_block())); | 2568 empty->Finish(new HGoto(subgraph->entry_block())); |
| 2668 } | 2569 } |
| 2669 } | 2570 } |
| 2670 | 2571 |
| 2671 // Check for fall-through from previous statement block. | 2572 // Check for fall-through from previous statement block. |
| 2672 if (previous_subgraph != NULL && previous_subgraph->HasExit()) { | 2573 if (previous_subgraph != NULL && previous_subgraph->exit_block() != NULL) { |
| 2673 if (subgraph == NULL) subgraph = CreateEmptySubgraph(); | 2574 if (subgraph == NULL) subgraph = CreateEmptySubgraph(); |
| 2674 previous_subgraph->exit_block()-> | 2575 previous_subgraph->exit_block()-> |
| 2675 Finish(new HGoto(subgraph->entry_block())); | 2576 Finish(new HGoto(subgraph->entry_block())); |
| 2676 } | 2577 } |
| 2677 | 2578 |
| 2678 if (subgraph != NULL) { | 2579 if (subgraph != NULL) { |
| 2679 ADD_TO_SUBGRAPH(subgraph, clause->statements()); | 2580 BreakAndContinueInfo break_info(stmt); |
| 2680 HBasicBlock* break_block = subgraph->BundleBreak(stmt); | 2581 { BreakAndContinueScope push(&break_info, this); |
| 2681 if (break_block != NULL) { | 2582 ADD_TO_SUBGRAPH(subgraph, clause->statements()); |
| 2682 break_block->Finish(new HGoto(single_exit_block)); | 2583 } |
| 2584 if (break_info.break_block() != NULL) { |
| 2585 break_info.break_block()->SetJoinId(stmt->ExitId()); |
| 2586 break_info.break_block()->Finish(new HGoto(single_exit_block)); |
| 2683 } | 2587 } |
| 2684 } | 2588 } |
| 2685 | 2589 |
| 2686 previous_subgraph = subgraph; | 2590 previous_subgraph = subgraph; |
| 2687 } | 2591 } |
| 2688 | 2592 |
| 2689 // If the last statement block has a fall-through, connect it to the | 2593 // If the last statement block has a fall-through, connect it to the |
| 2690 // single exit block. | 2594 // single exit block. |
| 2691 if (previous_subgraph != NULL && previous_subgraph->HasExit()) { | 2595 if (previous_subgraph != NULL && previous_subgraph->exit_block() != NULL) { |
| 2692 previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block)); | 2596 previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block)); |
| 2693 } | 2597 } |
| 2694 | 2598 |
| 2695 // If there is no default clause finish the last comparison's false target. | 2599 // If there is no default clause finish the last comparison's false target. |
| 2696 if (!last_false_block->IsFinished()) { | 2600 if (!last_false_block->IsFinished()) { |
| 2697 last_false_block->Finish(new HGoto(single_exit_block)); | 2601 last_false_block->Finish(new HGoto(single_exit_block)); |
| 2698 } | 2602 } |
| 2699 | 2603 |
| 2700 if (single_exit_block->HasPredecessor()) { | 2604 if (single_exit_block->HasPredecessor()) { |
| 2701 current_subgraph_->set_exit_block(single_exit_block); | 2605 set_current_block(single_exit_block); |
| 2702 } else { | 2606 } else { |
| 2703 current_subgraph_->set_exit_block(NULL); | 2607 set_current_block(NULL); |
| 2704 } | 2608 } |
| 2705 } | 2609 } |
| 2706 | 2610 |
| 2707 bool HGraph::HasOsrEntryAt(IterationStatement* statement) { | 2611 bool HGraph::HasOsrEntryAt(IterationStatement* statement) { |
| 2708 return statement->OsrEntryId() == info()->osr_ast_id(); | 2612 return statement->OsrEntryId() == info()->osr_ast_id(); |
| 2709 } | 2613 } |
| 2710 | 2614 |
| 2711 | 2615 |
| 2712 void HSubgraph::PreProcessOsrEntry(IterationStatement* statement) { | 2616 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { |
| 2713 if (!graph()->HasOsrEntryAt(statement)) return; | 2617 if (!graph()->HasOsrEntryAt(statement)) return; |
| 2714 | 2618 |
| 2715 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); | 2619 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); |
| 2716 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); | 2620 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); |
| 2717 HValue* true_value = graph()->GetConstantTrue(); | 2621 HValue* true_value = graph()->GetConstantTrue(); |
| 2718 HTest* test = new HTest(true_value, non_osr_entry, osr_entry); | 2622 HTest* test = new HTest(true_value, non_osr_entry, osr_entry); |
| 2719 exit_block()->Finish(test); | 2623 current_block()->Finish(test); |
| 2720 | 2624 |
| 2721 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); | 2625 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); |
| 2722 non_osr_entry->Goto(loop_predecessor); | 2626 non_osr_entry->Goto(loop_predecessor); |
| 2723 | 2627 |
| 2628 set_current_block(osr_entry); |
| 2724 int osr_entry_id = statement->OsrEntryId(); | 2629 int osr_entry_id = statement->OsrEntryId(); |
| 2725 // We want the correct environment at the OsrEntry instruction. Build | 2630 // We want the correct environment at the OsrEntry instruction. Build |
| 2726 // it explicitly. The expression stack should be empty. | 2631 // it explicitly. The expression stack should be empty. |
| 2727 int count = osr_entry->last_environment()->length(); | 2632 int count = environment()->length(); |
| 2728 ASSERT(count == (osr_entry->last_environment()->parameter_count() + | 2633 ASSERT(count == |
| 2729 osr_entry->last_environment()->local_count())); | 2634 (environment()->parameter_count() + environment()->local_count())); |
| 2730 for (int i = 0; i < count; ++i) { | 2635 for (int i = 0; i < count; ++i) { |
| 2731 HUnknownOSRValue* unknown = new HUnknownOSRValue; | 2636 HUnknownOSRValue* unknown = new HUnknownOSRValue; |
| 2732 osr_entry->AddInstruction(unknown); | 2637 AddInstruction(unknown); |
| 2733 osr_entry->last_environment()->Bind(i, unknown); | 2638 environment()->Bind(i, unknown); |
| 2734 } | 2639 } |
| 2735 | 2640 |
| 2736 osr_entry->AddSimulate(osr_entry_id); | 2641 AddSimulate(osr_entry_id); |
| 2737 osr_entry->AddInstruction(new HOsrEntry(osr_entry_id)); | 2642 AddInstruction(new HOsrEntry(osr_entry_id)); |
| 2738 osr_entry->Goto(loop_predecessor); | 2643 current_block()->Goto(loop_predecessor); |
| 2739 loop_predecessor->SetJoinId(statement->EntryId()); | 2644 loop_predecessor->SetJoinId(statement->EntryId()); |
| 2740 set_exit_block(loop_predecessor); | 2645 set_current_block(loop_predecessor); |
| 2741 } | 2646 } |
| 2742 | 2647 |
| 2743 | 2648 |
| 2744 void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { | 2649 void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { |
| 2745 ASSERT(subgraph()->HasExit()); | 2650 ASSERT(current_block() != NULL); |
| 2746 subgraph()->PreProcessOsrEntry(stmt); | 2651 PreProcessOsrEntry(stmt); |
| 2652 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); |
| 2653 current_block()->Goto(loop_entry, false); |
| 2654 set_current_block(loop_entry); |
| 2747 | 2655 |
| 2748 HSubgraph* body_graph = CreateLoopHeaderSubgraph(environment()); | 2656 BreakAndContinueInfo break_info(stmt); |
| 2749 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | 2657 { BreakAndContinueScope push(&break_info, this); |
| 2750 body_graph->ResolveContinue(stmt); | 2658 Visit(stmt->body()); |
| 2751 | 2659 CHECK_BAILOUT; |
| 2752 if (!body_graph->HasExit() || stmt->cond()->ToBooleanIsTrue()) { | |
| 2753 current_subgraph_->AppendEndless(body_graph, stmt); | |
| 2754 } else { | |
| 2755 HSubgraph* go_back = CreateEmptySubgraph(); | |
| 2756 HSubgraph* exit = CreateEmptySubgraph(); | |
| 2757 { | |
| 2758 SubgraphScope scope(this, body_graph); | |
| 2759 VISIT_FOR_CONTROL(stmt->cond(), | |
| 2760 go_back->entry_block(), | |
| 2761 exit->entry_block()); | |
| 2762 go_back->entry_block()->SetJoinId(stmt->BackEdgeId()); | |
| 2763 exit->entry_block()->SetJoinId(stmt->ExitId()); | |
| 2764 } | |
| 2765 current_subgraph_->AppendDoWhile(body_graph, stmt, go_back, exit); | |
| 2766 } | 2660 } |
| 2767 } | 2661 HBasicBlock* body_exit = |
| 2768 | 2662 JoinContinue(stmt, current_block(), break_info.continue_block()); |
| 2769 | 2663 HBasicBlock* loop_successor = NULL; |
| 2770 bool HGraphBuilder::ShouldPeel(HSubgraph* cond, HSubgraph* body) { | 2664 if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) { |
| 2771 return FLAG_use_peeling; | 2665 set_current_block(body_exit); |
| 2666 // The block for a true condition, the actual predecessor block of the |
| 2667 // back edge. |
| 2668 body_exit = graph()->CreateBasicBlock(); |
| 2669 loop_successor = graph()->CreateBasicBlock(); |
| 2670 VISIT_FOR_CONTROL(stmt->cond(), body_exit, loop_successor); |
| 2671 body_exit->SetJoinId(stmt->BackEdgeId()); |
| 2672 loop_successor->SetJoinId(stmt->ExitId()); |
| 2673 } |
| 2674 HBasicBlock* loop_exit = CreateLoop(stmt, |
| 2675 loop_entry, |
| 2676 body_exit, |
| 2677 loop_successor, |
| 2678 break_info.break_block()); |
| 2679 set_current_block(loop_exit); |
| 2772 } | 2680 } |
| 2773 | 2681 |
| 2774 | 2682 |
| 2775 void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { | 2683 void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { |
| 2776 ASSERT(subgraph()->HasExit()); | 2684 ASSERT(current_block() != NULL); |
| 2777 subgraph()->PreProcessOsrEntry(stmt); | 2685 PreProcessOsrEntry(stmt); |
| 2686 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); |
| 2687 current_block()->Goto(loop_entry, false); |
| 2688 set_current_block(loop_entry); |
| 2778 | 2689 |
| 2779 HSubgraph* cond_graph = NULL; | 2690 // If the condition is constant true, do not generate a branch. |
| 2780 HSubgraph* body_graph = NULL; | 2691 HBasicBlock* loop_successor = NULL; |
| 2781 HSubgraph* exit_graph = NULL; | 2692 if (!stmt->cond()->ToBooleanIsTrue()) { |
| 2782 | 2693 HBasicBlock* body_entry = graph()->CreateBasicBlock(); |
| 2783 // If the condition is constant true, do not generate a condition subgraph. | 2694 loop_successor = graph()->CreateBasicBlock(); |
| 2784 if (stmt->cond()->ToBooleanIsTrue()) { | 2695 VISIT_FOR_CONTROL(stmt->cond(), body_entry, loop_successor); |
| 2785 body_graph = CreateLoopHeaderSubgraph(environment()); | 2696 body_entry->SetJoinId(stmt->BodyId()); |
| 2786 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | 2697 loop_successor->SetJoinId(stmt->ExitId()); |
| 2787 } else { | 2698 set_current_block(body_entry); |
| 2788 cond_graph = CreateLoopHeaderSubgraph(environment()); | |
| 2789 body_graph = CreateEmptySubgraph(); | |
| 2790 exit_graph = CreateEmptySubgraph(); | |
| 2791 { | |
| 2792 SubgraphScope scope(this, cond_graph); | |
| 2793 VISIT_FOR_CONTROL(stmt->cond(), | |
| 2794 body_graph->entry_block(), | |
| 2795 exit_graph->entry_block()); | |
| 2796 body_graph->entry_block()->SetJoinId(stmt->BodyId()); | |
| 2797 exit_graph->entry_block()->SetJoinId(stmt->ExitId()); | |
| 2798 } | |
| 2799 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | |
| 2800 } | 2699 } |
| 2801 | 2700 |
| 2802 body_graph->ResolveContinue(stmt); | 2701 BreakAndContinueInfo break_info(stmt); |
| 2803 | 2702 { BreakAndContinueScope push(&break_info, this); |
| 2804 if (cond_graph != NULL) { | 2703 Visit(stmt->body()); |
| 2805 AppendPeeledWhile(stmt, cond_graph, body_graph, exit_graph); | 2704 CHECK_BAILOUT; |
| 2806 } else { | |
| 2807 // TODO(fschneider): Implement peeling for endless loops as well. | |
| 2808 current_subgraph_->AppendEndless(body_graph, stmt); | |
| 2809 } | 2705 } |
| 2810 } | 2706 HBasicBlock* body_exit = |
| 2811 | 2707 JoinContinue(stmt, current_block(), break_info.continue_block()); |
| 2812 | 2708 HBasicBlock* loop_exit = CreateLoop(stmt, |
| 2813 void HGraphBuilder::AppendPeeledWhile(IterationStatement* stmt, | 2709 loop_entry, |
| 2814 HSubgraph* cond_graph, | 2710 body_exit, |
| 2815 HSubgraph* body_graph, | 2711 loop_successor, |
| 2816 HSubgraph* exit_graph) { | 2712 break_info.break_block()); |
| 2817 HSubgraph* loop = NULL; | 2713 set_current_block(loop_exit); |
| 2818 if (body_graph->HasExit() && stmt != peeled_statement_ && | |
| 2819 ShouldPeel(cond_graph, body_graph)) { | |
| 2820 // Save the last peeled iteration statement to prevent infinite recursion. | |
| 2821 IterationStatement* outer_peeled_statement = peeled_statement_; | |
| 2822 peeled_statement_ = stmt; | |
| 2823 loop = CreateGotoSubgraph(body_graph->environment()); | |
| 2824 ADD_TO_SUBGRAPH(loop, stmt); | |
| 2825 peeled_statement_ = outer_peeled_statement; | |
| 2826 } | |
| 2827 current_subgraph_->AppendWhile(cond_graph, body_graph, stmt, loop, | |
| 2828 exit_graph); | |
| 2829 } | 2714 } |
| 2830 | 2715 |
| 2831 | 2716 |
| 2832 void HGraphBuilder::VisitForStatement(ForStatement* stmt) { | 2717 void HGraphBuilder::VisitForStatement(ForStatement* stmt) { |
| 2833 // Only visit the init statement in the peeled part of the loop. | 2718 if (stmt->init() != NULL) { |
| 2834 if (stmt->init() != NULL && peeled_statement_ != stmt) { | |
| 2835 Visit(stmt->init()); | 2719 Visit(stmt->init()); |
| 2836 CHECK_BAILOUT; | 2720 CHECK_BAILOUT; |
| 2837 } | 2721 } |
| 2838 ASSERT(subgraph()->HasExit()); | 2722 ASSERT(current_block() != NULL); |
| 2839 subgraph()->PreProcessOsrEntry(stmt); | 2723 PreProcessOsrEntry(stmt); |
| 2724 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); |
| 2725 current_block()->Goto(loop_entry, false); |
| 2726 set_current_block(loop_entry); |
| 2840 | 2727 |
| 2841 HSubgraph* cond_graph = NULL; | 2728 HBasicBlock* loop_successor = NULL; |
| 2842 HSubgraph* body_graph = NULL; | |
| 2843 HSubgraph* exit_graph = NULL; | |
| 2844 if (stmt->cond() != NULL) { | 2729 if (stmt->cond() != NULL) { |
| 2845 cond_graph = CreateLoopHeaderSubgraph(environment()); | 2730 HBasicBlock* body_entry = graph()->CreateBasicBlock(); |
| 2846 body_graph = CreateEmptySubgraph(); | 2731 loop_successor = graph()->CreateBasicBlock(); |
| 2847 exit_graph = CreateEmptySubgraph(); | 2732 VISIT_FOR_CONTROL(stmt->cond(), body_entry, loop_successor); |
| 2848 { | 2733 body_entry->SetJoinId(stmt->BodyId()); |
| 2849 SubgraphScope scope(this, cond_graph); | 2734 loop_successor->SetJoinId(stmt->ExitId()); |
| 2850 VISIT_FOR_CONTROL(stmt->cond(), | 2735 set_current_block(body_entry); |
| 2851 body_graph->entry_block(), | |
| 2852 exit_graph->entry_block()); | |
| 2853 body_graph->entry_block()->SetJoinId(stmt->BodyId()); | |
| 2854 exit_graph->entry_block()->SetJoinId(stmt->ExitId()); | |
| 2855 } | |
| 2856 } else { | |
| 2857 body_graph = CreateLoopHeaderSubgraph(environment()); | |
| 2858 } | |
| 2859 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | |
| 2860 | |
| 2861 HSubgraph* next_graph = NULL; | |
| 2862 body_graph->ResolveContinue(stmt); | |
| 2863 | |
| 2864 if (stmt->next() != NULL && body_graph->HasExit()) { | |
| 2865 next_graph = CreateGotoSubgraph(body_graph->environment()); | |
| 2866 ADD_TO_SUBGRAPH(next_graph, stmt->next()); | |
| 2867 body_graph->Append(next_graph, NULL); | |
| 2868 next_graph->entry_block()->SetJoinId(stmt->ContinueId()); | |
| 2869 } | 2736 } |
| 2870 | 2737 |
| 2871 if (cond_graph != NULL) { | 2738 BreakAndContinueInfo break_info(stmt); |
| 2872 AppendPeeledWhile(stmt, cond_graph, body_graph, exit_graph); | 2739 { BreakAndContinueScope push(&break_info, this); |
| 2873 } else { | 2740 Visit(stmt->body()); |
| 2874 current_subgraph_->AppendEndless(body_graph, stmt); | 2741 CHECK_BAILOUT; |
| 2875 } | 2742 } |
| 2743 HBasicBlock* body_exit = |
| 2744 JoinContinue(stmt, current_block(), break_info.continue_block()); |
| 2745 |
| 2746 if (stmt->next() != NULL && body_exit != NULL) { |
| 2747 set_current_block(body_exit); |
| 2748 Visit(stmt->next()); |
| 2749 CHECK_BAILOUT; |
| 2750 body_exit = current_block(); |
| 2751 } |
| 2752 |
| 2753 HBasicBlock* loop_exit = CreateLoop(stmt, |
| 2754 loop_entry, |
| 2755 body_exit, |
| 2756 loop_successor, |
| 2757 break_info.break_block()); |
| 2758 set_current_block(loop_exit); |
| 2876 } | 2759 } |
| 2877 | 2760 |
| 2878 | 2761 |
| 2879 void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) { | 2762 void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) { |
| 2880 BAILOUT("ForInStatement"); | 2763 BAILOUT("ForInStatement"); |
| 2881 } | 2764 } |
| 2882 | 2765 |
| 2883 | 2766 |
| 2884 void HGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { | 2767 void HGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { |
| 2885 BAILOUT("TryCatchStatement"); | 2768 BAILOUT("TryCatchStatement"); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2906 } | 2789 } |
| 2907 | 2790 |
| 2908 | 2791 |
| 2909 void HGraphBuilder::VisitSharedFunctionInfoLiteral( | 2792 void HGraphBuilder::VisitSharedFunctionInfoLiteral( |
| 2910 SharedFunctionInfoLiteral* expr) { | 2793 SharedFunctionInfoLiteral* expr) { |
| 2911 BAILOUT("SharedFunctionInfoLiteral"); | 2794 BAILOUT("SharedFunctionInfoLiteral"); |
| 2912 } | 2795 } |
| 2913 | 2796 |
| 2914 | 2797 |
| 2915 void HGraphBuilder::VisitConditional(Conditional* expr) { | 2798 void HGraphBuilder::VisitConditional(Conditional* expr) { |
| 2916 HSubgraph* then_graph = CreateEmptySubgraph(); | 2799 HBasicBlock* cond_true = graph()->CreateBasicBlock(); |
| 2917 HSubgraph* else_graph = CreateEmptySubgraph(); | 2800 HBasicBlock* cond_false = graph()->CreateBasicBlock(); |
| 2918 VISIT_FOR_CONTROL(expr->condition(), | 2801 VISIT_FOR_CONTROL(expr->condition(), cond_true, cond_false); |
| 2919 then_graph->entry_block(), | 2802 cond_true->SetJoinId(expr->ThenId()); |
| 2920 else_graph->entry_block()); | 2803 cond_false->SetJoinId(expr->ElseId()); |
| 2921 | 2804 |
| 2922 then_graph->entry_block()->SetJoinId(expr->ThenId()); | 2805 // TOOD(kmillikin): Visit the subexpressions in the same AST context as |
| 2923 ADD_TO_SUBGRAPH(then_graph, expr->then_expression()); | 2806 // the whole expression. |
| 2807 set_current_block(cond_true); |
| 2808 VISIT_FOR_VALUE(expr->then_expression()); |
| 2809 HBasicBlock* other = current_block(); |
| 2924 | 2810 |
| 2925 else_graph->entry_block()->SetJoinId(expr->ElseId()); | 2811 set_current_block(cond_false); |
| 2926 ADD_TO_SUBGRAPH(else_graph, expr->else_expression()); | 2812 VISIT_FOR_VALUE(expr->else_expression()); |
| 2927 | 2813 |
| 2928 current_subgraph_->AppendJoin(then_graph, else_graph, expr); | 2814 HBasicBlock* join = CreateJoin(other, current_block(), expr->id()); |
| 2815 set_current_block(join); |
| 2929 ast_context()->ReturnValue(Pop()); | 2816 ast_context()->ReturnValue(Pop()); |
| 2930 } | 2817 } |
| 2931 | 2818 |
| 2932 | 2819 |
| 2933 void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, | 2820 void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, |
| 2934 LookupResult* lookup, | 2821 LookupResult* lookup, |
| 2935 bool is_store) { | 2822 bool is_store) { |
| 2936 if (var->is_this()) { | 2823 if (var->is_this()) { |
| 2937 BAILOUT("global this reference"); | 2824 BAILOUT("global this reference"); |
| 2938 } | 2825 } |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3015 | 2902 |
| 3016 void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { | 2903 void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 3017 HRegExpLiteral* instr = new HRegExpLiteral(expr->pattern(), | 2904 HRegExpLiteral* instr = new HRegExpLiteral(expr->pattern(), |
| 3018 expr->flags(), | 2905 expr->flags(), |
| 3019 expr->literal_index()); | 2906 expr->literal_index()); |
| 3020 ast_context()->ReturnInstruction(instr, expr->id()); | 2907 ast_context()->ReturnInstruction(instr, expr->id()); |
| 3021 } | 2908 } |
| 3022 | 2909 |
| 3023 | 2910 |
| 3024 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { | 2911 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
| 3025 HObjectLiteral* literal = (new HObjectLiteral(expr->constant_properties(), | 2912 HContext* context = new HContext; |
| 2913 AddInstruction(context); |
| 2914 HObjectLiteral* literal = (new HObjectLiteral(context, |
| 2915 expr->constant_properties(), |
| 3026 expr->fast_elements(), | 2916 expr->fast_elements(), |
| 3027 expr->literal_index(), | 2917 expr->literal_index(), |
| 3028 expr->depth())); | 2918 expr->depth())); |
| 3029 // The object is expected in the bailout environment during computation | 2919 // The object is expected in the bailout environment during computation |
| 3030 // of the property values and is the value of the entire expression. | 2920 // of the property values and is the value of the entire expression. |
| 3031 PushAndAdd(literal); | 2921 PushAndAdd(literal); |
| 3032 | 2922 |
| 3033 expr->CalculateEmitStore(); | 2923 expr->CalculateEmitStore(); |
| 3034 | 2924 |
| 3035 for (int i = 0; i < expr->properties()->length(); i++) { | 2925 for (int i = 0; i < expr->properties()->length(); i++) { |
| 3036 ObjectLiteral::Property* property = expr->properties()->at(i); | 2926 ObjectLiteral::Property* property = expr->properties()->at(i); |
| 3037 if (property->IsCompileTimeValue()) continue; | 2927 if (property->IsCompileTimeValue()) continue; |
| 3038 | 2928 |
| 3039 Literal* key = property->key(); | 2929 Literal* key = property->key(); |
| 3040 Expression* value = property->value(); | 2930 Expression* value = property->value(); |
| 3041 | 2931 |
| 3042 switch (property->kind()) { | 2932 switch (property->kind()) { |
| 3043 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 2933 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 3044 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 2934 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 3045 // Fall through. | 2935 // Fall through. |
| 3046 case ObjectLiteral::Property::COMPUTED: | 2936 case ObjectLiteral::Property::COMPUTED: |
| 3047 if (key->handle()->IsSymbol()) { | 2937 if (key->handle()->IsSymbol()) { |
| 3048 if (property->emit_store()) { | 2938 if (property->emit_store()) { |
| 3049 VISIT_FOR_VALUE(value); | 2939 VISIT_FOR_VALUE(value); |
| 3050 HValue* value = Pop(); | 2940 HValue* value = Pop(); |
| 3051 Handle<String> name = Handle<String>::cast(key->handle()); | 2941 Handle<String> name = Handle<String>::cast(key->handle()); |
| 3052 AddInstruction(new HStoreNamedGeneric(literal, name, value)); | 2942 HStoreNamedGeneric* store = |
| 2943 new HStoreNamedGeneric(context, literal, name, value); |
| 2944 AddInstruction(store); |
| 3053 AddSimulate(key->id()); | 2945 AddSimulate(key->id()); |
| 3054 } else { | 2946 } else { |
| 3055 VISIT_FOR_EFFECT(value); | 2947 VISIT_FOR_EFFECT(value); |
| 3056 } | 2948 } |
| 3057 break; | 2949 break; |
| 3058 } | 2950 } |
| 3059 // Fall through. | 2951 // Fall through. |
| 3060 case ObjectLiteral::Property::PROTOTYPE: | 2952 case ObjectLiteral::Property::PROTOTYPE: |
| 3061 case ObjectLiteral::Property::SETTER: | 2953 case ObjectLiteral::Property::SETTER: |
| 3062 case ObjectLiteral::Property::GETTER: | 2954 case ObjectLiteral::Property::GETTER: |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3105 } | 2997 } |
| 3106 ast_context()->ReturnValue(Pop()); | 2998 ast_context()->ReturnValue(Pop()); |
| 3107 } | 2999 } |
| 3108 | 3000 |
| 3109 | 3001 |
| 3110 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { | 3002 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { |
| 3111 BAILOUT("CatchExtensionObject"); | 3003 BAILOUT("CatchExtensionObject"); |
| 3112 } | 3004 } |
| 3113 | 3005 |
| 3114 | 3006 |
| 3115 HBasicBlock* HGraphBuilder::BuildTypeSwitch(ZoneMapList* maps, | 3007 HBasicBlock* HGraphBuilder::BuildTypeSwitch(HValue* receiver, |
| 3116 ZoneList<HSubgraph*>* subgraphs, | 3008 ZoneMapList* maps, |
| 3117 HValue* receiver, | 3009 ZoneList<HSubgraph*>* body_graphs, |
| 3010 HSubgraph* default_graph, |
| 3118 int join_id) { | 3011 int join_id) { |
| 3119 ASSERT(subgraphs->length() == (maps->length() + 1)); | 3012 ASSERT(maps->length() == body_graphs->length()); |
| 3013 HBasicBlock* join_block = graph()->CreateBasicBlock(); |
| 3014 AddInstruction(new HCheckNonSmi(receiver)); |
| 3120 | 3015 |
| 3121 // Build map compare subgraphs for all but the first map. | 3016 for (int i = 0; i < maps->length(); ++i) { |
| 3122 ZoneList<HSubgraph*> map_compare_subgraphs(maps->length() - 1); | 3017 // Build the branches, connect all the target subgraphs to the join |
| 3123 for (int i = maps->length() - 1; i > 0; --i) { | 3018 // block. Use the default as a target of the last branch. |
| 3124 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3019 HSubgraph* if_true = body_graphs->at(i); |
| 3125 SubgraphScope scope(this, subgraph); | 3020 HSubgraph* if_false = (i == maps->length() - 1) |
| 3126 HSubgraph* else_subgraph = | 3021 ? default_graph |
| 3127 (i == (maps->length() - 1)) | 3022 : CreateBranchSubgraph(environment()); |
| 3128 ? subgraphs->last() | 3023 HCompareMap* compare = |
| 3129 : map_compare_subgraphs.last(); | 3024 new HCompareMap(receiver, |
| 3130 HCompareMap* compare = new HCompareMap(receiver, | 3025 maps->at(i), |
| 3131 maps->at(i), | 3026 if_true->entry_block(), |
| 3132 subgraphs->at(i)->entry_block(), | 3027 if_false->entry_block()); |
| 3133 else_subgraph->entry_block()); | 3028 current_block()->Finish(compare); |
| 3134 current_subgraph_->exit_block()->Finish(compare); | 3029 |
| 3135 map_compare_subgraphs.Add(subgraph); | 3030 if (if_true->exit_block() != NULL) { |
| 3031 // In an effect context the value of the type switch is not needed. |
| 3032 // There is no need to merge it at the join block only to discard it. |
| 3033 if (ast_context()->IsEffect()) { |
| 3034 if_true->exit_block()->last_environment()->Drop(1); |
| 3035 } |
| 3036 if_true->exit_block()->Goto(join_block); |
| 3037 } |
| 3038 |
| 3039 set_current_block(if_false->exit_block()); |
| 3136 } | 3040 } |
| 3137 | 3041 |
| 3138 // Generate first map check to end the current block. | 3042 // Connect the default if necessary. |
| 3139 AddInstruction(new HCheckNonSmi(receiver)); | 3043 if (current_block() != NULL) { |
| 3140 HSubgraph* else_subgraph = | 3044 if (ast_context()->IsEffect()) { |
| 3141 (maps->length() == 1) ? subgraphs->at(1) : map_compare_subgraphs.last(); | 3045 environment()->Drop(1); |
| 3142 HCompareMap* compare = new HCompareMap(receiver, | |
| 3143 Handle<Map>(maps->first()), | |
| 3144 subgraphs->first()->entry_block(), | |
| 3145 else_subgraph->entry_block()); | |
| 3146 current_subgraph_->exit_block()->Finish(compare); | |
| 3147 | |
| 3148 // Join all the call subgraphs in a new basic block and make | |
| 3149 // this basic block the current basic block. | |
| 3150 HBasicBlock* join_block = graph_->CreateBasicBlock(); | |
| 3151 for (int i = 0; i < subgraphs->length(); ++i) { | |
| 3152 HSubgraph* subgraph = subgraphs->at(i); | |
| 3153 if (subgraph->HasExit()) { | |
| 3154 // In an effect context the value of the type switch is not needed. | |
| 3155 // There is no need to merge it at the join block only to discard it. | |
| 3156 HBasicBlock* subgraph_exit = subgraph->exit_block(); | |
| 3157 if (ast_context()->IsEffect()) { | |
| 3158 subgraph_exit->last_environment()->Drop(1); | |
| 3159 } | |
| 3160 subgraph_exit->Goto(join_block); | |
| 3161 } | 3046 } |
| 3047 current_block()->Goto(join_block); |
| 3162 } | 3048 } |
| 3163 | 3049 |
| 3164 if (join_block->predecessors()->is_empty()) return NULL; | 3050 if (join_block->predecessors()->is_empty()) return NULL; |
| 3165 join_block->SetJoinId(join_id); | 3051 join_block->SetJoinId(join_id); |
| 3166 return join_block; | 3052 return join_block; |
| 3167 } | 3053 } |
| 3168 | 3054 |
| 3169 | 3055 |
| 3170 // Sets the lookup result and returns true if the store can be inlined. | 3056 // Sets the lookup result and returns true if the store can be inlined. |
| 3171 static bool ComputeStoredField(Handle<Map> type, | 3057 static bool ComputeStoredField(Handle<Map> type, |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3222 // enable elimination of redundant checks after the transition store. | 3108 // enable elimination of redundant checks after the transition store. |
| 3223 instr->SetFlag(HValue::kChangesMaps); | 3109 instr->SetFlag(HValue::kChangesMaps); |
| 3224 } | 3110 } |
| 3225 return instr; | 3111 return instr; |
| 3226 } | 3112 } |
| 3227 | 3113 |
| 3228 | 3114 |
| 3229 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object, | 3115 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object, |
| 3230 Handle<String> name, | 3116 Handle<String> name, |
| 3231 HValue* value) { | 3117 HValue* value) { |
| 3232 return new HStoreNamedGeneric(object, name, value); | 3118 HContext* context = new HContext; |
| 3119 AddInstruction(context); |
| 3120 return new HStoreNamedGeneric(context, object, name, value); |
| 3233 } | 3121 } |
| 3234 | 3122 |
| 3235 | 3123 |
| 3236 HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object, | 3124 HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object, |
| 3237 HValue* value, | 3125 HValue* value, |
| 3238 Expression* expr) { | 3126 Expression* expr) { |
| 3239 Property* prop = (expr->AsProperty() != NULL) | 3127 Property* prop = (expr->AsProperty() != NULL) |
| 3240 ? expr->AsProperty() | 3128 ? expr->AsProperty() |
| 3241 : expr->AsAssignment()->target()->AsProperty(); | 3129 : expr->AsAssignment()->target()->AsProperty(); |
| 3242 Literal* key = prop->key()->AsLiteral(); | 3130 Literal* key = prop->key()->AsLiteral(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3255 } | 3143 } |
| 3256 | 3144 |
| 3257 | 3145 |
| 3258 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, | 3146 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
| 3259 HValue* object, | 3147 HValue* object, |
| 3260 HValue* value, | 3148 HValue* value, |
| 3261 ZoneMapList* types, | 3149 ZoneMapList* types, |
| 3262 Handle<String> name) { | 3150 Handle<String> name) { |
| 3263 int number_of_types = Min(types->length(), kMaxStorePolymorphism); | 3151 int number_of_types = Min(types->length(), kMaxStorePolymorphism); |
| 3264 ZoneMapList maps(number_of_types); | 3152 ZoneMapList maps(number_of_types); |
| 3265 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); | 3153 ZoneList<HSubgraph*> subgraphs(number_of_types); |
| 3266 bool needs_generic = (types->length() > kMaxStorePolymorphism); | 3154 bool needs_generic = (types->length() > kMaxStorePolymorphism); |
| 3267 | 3155 |
| 3268 // Build subgraphs for each of the specific maps. | 3156 // Build subgraphs for each of the specific maps. |
| 3269 // | 3157 // |
| 3270 // TODO(ager): We should recognize when the prototype chains for | 3158 // TODO(ager): We should recognize when the prototype chains for |
| 3271 // different maps are identical. In that case we can avoid | 3159 // different maps are identical. In that case we can avoid |
| 3272 // repeatedly generating the same prototype map checks. | 3160 // repeatedly generating the same prototype map checks. |
| 3273 for (int i = 0; i < number_of_types; ++i) { | 3161 for (int i = 0; i < number_of_types; ++i) { |
| 3274 Handle<Map> map = types->at(i); | 3162 Handle<Map> map = types->at(i); |
| 3275 LookupResult lookup; | 3163 LookupResult lookup; |
| 3276 if (ComputeStoredField(map, name, &lookup)) { | 3164 if (ComputeStoredField(map, name, &lookup)) { |
| 3277 maps.Add(map); | |
| 3278 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3165 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3279 SubgraphScope scope(this, subgraph); | 3166 SubgraphScope scope(this, subgraph); |
| 3280 HInstruction* instr = | 3167 HInstruction* instr = |
| 3281 BuildStoreNamedField(object, name, value, map, &lookup, false); | 3168 BuildStoreNamedField(object, name, value, map, &lookup, false); |
| 3282 Push(value); | 3169 Push(value); |
| 3283 instr->set_position(expr->position()); | 3170 instr->set_position(expr->position()); |
| 3284 AddInstruction(instr); | 3171 AddInstruction(instr); |
| 3172 maps.Add(map); |
| 3285 subgraphs.Add(subgraph); | 3173 subgraphs.Add(subgraph); |
| 3286 } else { | 3174 } else { |
| 3287 needs_generic = true; | 3175 needs_generic = true; |
| 3288 } | 3176 } |
| 3289 } | 3177 } |
| 3290 | 3178 |
| 3291 // If none of the properties were named fields we generate a | 3179 // If none of the properties were named fields we generate a |
| 3292 // generic store. | 3180 // generic store. |
| 3293 if (maps.length() == 0) { | 3181 if (maps.length() == 0) { |
| 3294 HInstruction* instr = new HStoreNamedGeneric(object, name, value); | 3182 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
| 3295 Push(value); | 3183 Push(value); |
| 3296 instr->set_position(expr->position()); | 3184 instr->set_position(expr->position()); |
| 3297 AddInstruction(instr); | 3185 AddInstruction(instr); |
| 3298 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3186 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3299 ast_context()->ReturnValue(Pop()); | 3187 ast_context()->ReturnValue(Pop()); |
| 3300 } else { | 3188 } else { |
| 3301 // Build subgraph for generic store through IC. | 3189 // Build subgraph for generic store through IC. |
| 3302 { | 3190 HSubgraph* default_graph = CreateBranchSubgraph(environment()); |
| 3303 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3191 { SubgraphScope scope(this, default_graph); |
| 3304 SubgraphScope scope(this, subgraph); | |
| 3305 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3192 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
| 3306 subgraph->FinishExit(new HDeoptimize()); | 3193 default_graph->exit_block()->FinishExit(new HDeoptimize()); |
| 3194 default_graph->set_exit_block(NULL); |
| 3307 } else { | 3195 } else { |
| 3308 HInstruction* instr = new HStoreNamedGeneric(object, name, value); | 3196 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
| 3309 Push(value); | 3197 Push(value); |
| 3310 instr->set_position(expr->position()); | 3198 instr->set_position(expr->position()); |
| 3311 AddInstruction(instr); | 3199 AddInstruction(instr); |
| 3312 } | 3200 } |
| 3313 subgraphs.Add(subgraph); | |
| 3314 } | 3201 } |
| 3315 | 3202 |
| 3316 HBasicBlock* new_exit_block = | 3203 HBasicBlock* new_exit_block = |
| 3317 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); | 3204 BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id()); |
| 3318 subgraph()->set_exit_block(new_exit_block); | 3205 set_current_block(new_exit_block); |
| 3319 // In an effect context, we did not materialized the value in the | 3206 // In an effect context, we did not materialized the value in the |
| 3320 // predecessor environments so there's no need to handle it here. | 3207 // predecessor environments so there's no need to handle it here. |
| 3321 if (subgraph()->HasExit() && !ast_context()->IsEffect()) { | 3208 if (current_block() != NULL && !ast_context()->IsEffect()) { |
| 3322 ast_context()->ReturnValue(Pop()); | 3209 ast_context()->ReturnValue(Pop()); |
| 3323 } | 3210 } |
| 3324 } | 3211 } |
| 3325 } | 3212 } |
| 3326 | 3213 |
| 3327 | 3214 |
| 3328 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { | 3215 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
| 3329 Property* prop = expr->target()->AsProperty(); | 3216 Property* prop = expr->target()->AsProperty(); |
| 3330 ASSERT(prop != NULL); | 3217 ASSERT(prop != NULL); |
| 3331 expr->RecordTypeFeedback(oracle()); | 3218 expr->RecordTypeFeedback(oracle()); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3348 LookupResult lookup; | 3235 LookupResult lookup; |
| 3349 | 3236 |
| 3350 if (expr->IsMonomorphic()) { | 3237 if (expr->IsMonomorphic()) { |
| 3351 instr = BuildStoreNamed(object, value, expr); | 3238 instr = BuildStoreNamed(object, value, expr); |
| 3352 | 3239 |
| 3353 } else if (types != NULL && types->length() > 1) { | 3240 } else if (types != NULL && types->length() > 1) { |
| 3354 HandlePolymorphicStoreNamedField(expr, object, value, types, name); | 3241 HandlePolymorphicStoreNamedField(expr, object, value, types, name); |
| 3355 return; | 3242 return; |
| 3356 | 3243 |
| 3357 } else { | 3244 } else { |
| 3358 instr = new HStoreNamedGeneric(object, name, value); | 3245 instr = BuildStoreNamedGeneric(object, name, value); |
| 3359 } | 3246 } |
| 3360 | 3247 |
| 3361 } else { | 3248 } else { |
| 3362 // Keyed store. | 3249 // Keyed store. |
| 3363 VISIT_FOR_VALUE(prop->key()); | 3250 VISIT_FOR_VALUE(prop->key()); |
| 3364 VISIT_FOR_VALUE(expr->value()); | 3251 VISIT_FOR_VALUE(expr->value()); |
| 3365 value = Pop(); | 3252 value = Pop(); |
| 3366 HValue* key = Pop(); | 3253 HValue* key = Pop(); |
| 3367 HValue* object = Pop(); | 3254 HValue* object = Pop(); |
| 3368 | 3255 |
| 3369 bool is_fast_elements = expr->IsMonomorphic() && | 3256 if (expr->IsMonomorphic()) { |
| 3370 expr->GetMonomorphicReceiverType()->has_fast_elements(); | 3257 Handle<Map> receiver_type(expr->GetMonomorphicReceiverType()); |
| 3371 | 3258 // An object has either fast elements or pixel array elements, but never |
| 3372 instr = is_fast_elements | 3259 // both. Pixel array maps that are assigned to pixel array elements are |
| 3373 ? BuildStoreKeyedFastElement(object, key, value, expr) | 3260 // always created with the fast elements flag cleared. |
| 3374 : BuildStoreKeyedGeneric(object, key, value); | 3261 if (receiver_type->has_pixel_array_elements()) { |
| 3262 instr = BuildStoreKeyedPixelArrayElement(object, key, value, expr); |
| 3263 } else if (receiver_type->has_fast_elements()) { |
| 3264 instr = BuildStoreKeyedFastElement(object, key, value, expr); |
| 3265 } |
| 3266 } |
| 3267 if (instr == NULL) { |
| 3268 instr = BuildStoreKeyedGeneric(object, key, value); |
| 3269 } |
| 3375 } | 3270 } |
| 3376 | 3271 |
| 3377 Push(value); | 3272 Push(value); |
| 3378 instr->set_position(expr->position()); | 3273 instr->set_position(expr->position()); |
| 3379 AddInstruction(instr); | 3274 AddInstruction(instr); |
| 3380 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3275 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3381 ast_context()->ReturnValue(Pop()); | 3276 ast_context()->ReturnValue(Pop()); |
| 3382 } | 3277 } |
| 3383 | 3278 |
| 3384 | 3279 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 3408 VariableProxy* proxy = target->AsVariableProxy(); | 3303 VariableProxy* proxy = target->AsVariableProxy(); |
| 3409 Variable* var = proxy->AsVariable(); | 3304 Variable* var = proxy->AsVariable(); |
| 3410 Property* prop = target->AsProperty(); | 3305 Property* prop = target->AsProperty(); |
| 3411 ASSERT(var == NULL || prop == NULL); | 3306 ASSERT(var == NULL || prop == NULL); |
| 3412 | 3307 |
| 3413 // We have a second position recorded in the FullCodeGenerator to have | 3308 // We have a second position recorded in the FullCodeGenerator to have |
| 3414 // type feedback for the binary operation. | 3309 // type feedback for the binary operation. |
| 3415 BinaryOperation* operation = expr->binary_operation(); | 3310 BinaryOperation* operation = expr->binary_operation(); |
| 3416 | 3311 |
| 3417 if (var != NULL) { | 3312 if (var != NULL) { |
| 3418 if (!var->is_global() && !var->IsStackAllocated()) { | |
| 3419 BAILOUT("non-stack/non-global in compound assignment"); | |
| 3420 } | |
| 3421 | |
| 3422 VISIT_FOR_VALUE(operation); | 3313 VISIT_FOR_VALUE(operation); |
| 3423 | 3314 |
| 3424 if (var->is_global()) { | 3315 if (var->is_global()) { |
| 3425 HandleGlobalVariableAssignment(var, | 3316 HandleGlobalVariableAssignment(var, |
| 3426 Top(), | 3317 Top(), |
| 3427 expr->position(), | 3318 expr->position(), |
| 3428 expr->AssignmentId()); | 3319 expr->AssignmentId()); |
| 3320 } else if (var->IsStackAllocated()) { |
| 3321 Bind(var, Top()); |
| 3322 } else if (var->IsContextSlot()) { |
| 3323 HValue* context = BuildContextChainWalk(var); |
| 3324 int index = var->AsSlot()->index(); |
| 3325 HStoreContextSlot* instr = new HStoreContextSlot(context, index, Top()); |
| 3326 AddInstruction(instr); |
| 3327 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3429 } else { | 3328 } else { |
| 3430 Bind(var, Top()); | 3329 BAILOUT("compound assignment to lookup slot"); |
| 3431 } | 3330 } |
| 3432 ast_context()->ReturnValue(Pop()); | 3331 ast_context()->ReturnValue(Pop()); |
| 3433 | 3332 |
| 3434 } else if (prop != NULL) { | 3333 } else if (prop != NULL) { |
| 3435 prop->RecordTypeFeedback(oracle()); | 3334 prop->RecordTypeFeedback(oracle()); |
| 3436 | 3335 |
| 3437 if (prop->key()->IsPropertyName()) { | 3336 if (prop->key()->IsPropertyName()) { |
| 3438 // Named property. | 3337 // Named property. |
| 3439 VISIT_FOR_VALUE(prop->obj()); | 3338 VISIT_FOR_VALUE(prop->obj()); |
| 3440 HValue* obj = Top(); | 3339 HValue* obj = Top(); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 3468 | 3367 |
| 3469 } else { | 3368 } else { |
| 3470 // Keyed property. | 3369 // Keyed property. |
| 3471 VISIT_FOR_VALUE(prop->obj()); | 3370 VISIT_FOR_VALUE(prop->obj()); |
| 3472 VISIT_FOR_VALUE(prop->key()); | 3371 VISIT_FOR_VALUE(prop->key()); |
| 3473 HValue* obj = environment()->ExpressionStackAt(1); | 3372 HValue* obj = environment()->ExpressionStackAt(1); |
| 3474 HValue* key = environment()->ExpressionStackAt(0); | 3373 HValue* key = environment()->ExpressionStackAt(0); |
| 3475 | 3374 |
| 3476 bool is_fast_elements = prop->IsMonomorphic() && | 3375 bool is_fast_elements = prop->IsMonomorphic() && |
| 3477 prop->GetMonomorphicReceiverType()->has_fast_elements(); | 3376 prop->GetMonomorphicReceiverType()->has_fast_elements(); |
| 3478 | |
| 3479 HInstruction* load = is_fast_elements | 3377 HInstruction* load = is_fast_elements |
| 3480 ? BuildLoadKeyedFastElement(obj, key, prop) | 3378 ? BuildLoadKeyedFastElement(obj, key, prop) |
| 3481 : BuildLoadKeyedGeneric(obj, key); | 3379 : BuildLoadKeyedGeneric(obj, key); |
| 3482 PushAndAdd(load); | 3380 PushAndAdd(load); |
| 3483 if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); | 3381 if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); |
| 3484 | 3382 |
| 3485 VISIT_FOR_VALUE(expr->value()); | 3383 VISIT_FOR_VALUE(expr->value()); |
| 3486 HValue* right = Pop(); | 3384 HValue* right = Pop(); |
| 3487 HValue* left = Pop(); | 3385 HValue* left = Pop(); |
| 3488 | 3386 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3573 // assignments, count operations, or for-in. Consequently throw can | 3471 // assignments, count operations, or for-in. Consequently throw can |
| 3574 // currently only occur in an effect context. | 3472 // currently only occur in an effect context. |
| 3575 ASSERT(ast_context()->IsEffect()); | 3473 ASSERT(ast_context()->IsEffect()); |
| 3576 VISIT_FOR_VALUE(expr->exception()); | 3474 VISIT_FOR_VALUE(expr->exception()); |
| 3577 | 3475 |
| 3578 HValue* value = environment()->Pop(); | 3476 HValue* value = environment()->Pop(); |
| 3579 HThrow* instr = new HThrow(value); | 3477 HThrow* instr = new HThrow(value); |
| 3580 instr->set_position(expr->position()); | 3478 instr->set_position(expr->position()); |
| 3581 AddInstruction(instr); | 3479 AddInstruction(instr); |
| 3582 AddSimulate(expr->id()); | 3480 AddSimulate(expr->id()); |
| 3583 current_subgraph_->FinishExit(new HAbnormalExit); | 3481 current_block()->FinishExit(new HAbnormalExit); |
| 3482 set_current_block(NULL); |
| 3584 } | 3483 } |
| 3585 | 3484 |
| 3586 | 3485 |
| 3587 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, | 3486 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
| 3588 HValue* object, | 3487 HValue* object, |
| 3589 ZoneMapList* types, | 3488 ZoneMapList* types, |
| 3590 Handle<String> name) { | 3489 Handle<String> name) { |
| 3591 int number_of_types = Min(types->length(), kMaxLoadPolymorphism); | 3490 int number_of_types = Min(types->length(), kMaxLoadPolymorphism); |
| 3592 ZoneMapList maps(number_of_types); | 3491 ZoneMapList maps(number_of_types); |
| 3593 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); | 3492 ZoneList<HSubgraph*> subgraphs(number_of_types); |
| 3594 bool needs_generic = (types->length() > kMaxLoadPolymorphism); | 3493 bool needs_generic = (types->length() > kMaxLoadPolymorphism); |
| 3595 | 3494 |
| 3596 // Build subgraphs for each of the specific maps. | 3495 // Build subgraphs for each of the specific maps. |
| 3597 // | 3496 // |
| 3598 // TODO(ager): We should recognize when the prototype chains for | 3497 // TODO(ager): We should recognize when the prototype chains for |
| 3599 // different maps are identical. In that case we can avoid | 3498 // different maps are identical. In that case we can avoid |
| 3600 // repeatedly generating the same prototype map checks. | 3499 // repeatedly generating the same prototype map checks. |
| 3601 for (int i = 0; i < number_of_types; ++i) { | 3500 for (int i = 0; i < number_of_types; ++i) { |
| 3602 Handle<Map> map = types->at(i); | 3501 Handle<Map> map = types->at(i); |
| 3603 LookupResult lookup; | 3502 LookupResult lookup; |
| 3604 map->LookupInDescriptors(NULL, *name, &lookup); | 3503 map->LookupInDescriptors(NULL, *name, &lookup); |
| 3605 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3504 if (lookup.IsProperty() && lookup.type() == FIELD) { |
| 3606 maps.Add(map); | |
| 3607 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3505 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3608 SubgraphScope scope(this, subgraph); | 3506 SubgraphScope scope(this, subgraph); |
| 3609 HLoadNamedField* instr = | 3507 HLoadNamedField* instr = |
| 3610 BuildLoadNamedField(object, expr, map, &lookup, false); | 3508 BuildLoadNamedField(object, expr, map, &lookup, false); |
| 3611 instr->set_position(expr->position()); | 3509 instr->set_position(expr->position()); |
| 3612 instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads. | 3510 instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads. |
| 3613 PushAndAdd(instr); | 3511 PushAndAdd(instr); |
| 3512 maps.Add(map); |
| 3614 subgraphs.Add(subgraph); | 3513 subgraphs.Add(subgraph); |
| 3615 } else { | 3514 } else { |
| 3616 needs_generic = true; | 3515 needs_generic = true; |
| 3617 } | 3516 } |
| 3618 } | 3517 } |
| 3619 | 3518 |
| 3620 // If none of the properties were named fields we generate a | 3519 // If none of the properties were named fields we generate a |
| 3621 // generic load. | 3520 // generic load. |
| 3622 if (maps.length() == 0) { | 3521 if (maps.length() == 0) { |
| 3623 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3522 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
| 3624 instr->set_position(expr->position()); | 3523 instr->set_position(expr->position()); |
| 3625 ast_context()->ReturnInstruction(instr, expr->id()); | 3524 ast_context()->ReturnInstruction(instr, expr->id()); |
| 3626 } else { | 3525 } else { |
| 3627 // Build subgraph for generic load through IC. | 3526 // Build subgraph for generic load through IC. |
| 3628 { | 3527 HSubgraph* default_graph = CreateBranchSubgraph(environment()); |
| 3629 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3528 { SubgraphScope scope(this, default_graph); |
| 3630 SubgraphScope scope(this, subgraph); | |
| 3631 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3529 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
| 3632 subgraph->FinishExit(new HDeoptimize()); | 3530 default_graph->exit_block()->FinishExit(new HDeoptimize()); |
| 3531 default_graph->set_exit_block(NULL); |
| 3633 } else { | 3532 } else { |
| 3634 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3533 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
| 3635 instr->set_position(expr->position()); | 3534 instr->set_position(expr->position()); |
| 3636 PushAndAdd(instr); | 3535 PushAndAdd(instr); |
| 3637 } | 3536 } |
| 3638 subgraphs.Add(subgraph); | |
| 3639 } | 3537 } |
| 3640 | 3538 |
| 3641 HBasicBlock* new_exit_block = | 3539 HBasicBlock* new_exit_block = |
| 3642 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); | 3540 BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id()); |
| 3643 subgraph()->set_exit_block(new_exit_block); | 3541 set_current_block(new_exit_block); |
| 3644 // In an effect context, we did not materialized the value in the | 3542 // In an effect context, we did not materialized the value in the |
| 3645 // predecessor environments so there's no need to handle it here. | 3543 // predecessor environments so there's no need to handle it here. |
| 3646 if (subgraph()->HasExit() && !ast_context()->IsEffect()) { | 3544 if (current_block() != NULL && !ast_context()->IsEffect()) { |
| 3647 ast_context()->ReturnValue(Pop()); | 3545 ast_context()->ReturnValue(Pop()); |
| 3648 } | 3546 } |
| 3649 } | 3547 } |
| 3650 } | 3548 } |
| 3651 | 3549 |
| 3652 | 3550 |
| 3653 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, | 3551 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, |
| 3654 Property* expr, | 3552 Property* expr, |
| 3655 Handle<Map> type, | 3553 Handle<Map> type, |
| 3656 LookupResult* lookup, | 3554 LookupResult* lookup, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3671 int offset = (index * kPointerSize) + FixedArray::kHeaderSize; | 3569 int offset = (index * kPointerSize) + FixedArray::kHeaderSize; |
| 3672 return new HLoadNamedField(object, false, offset); | 3570 return new HLoadNamedField(object, false, offset); |
| 3673 } | 3571 } |
| 3674 } | 3572 } |
| 3675 | 3573 |
| 3676 | 3574 |
| 3677 HInstruction* HGraphBuilder::BuildLoadNamedGeneric(HValue* obj, | 3575 HInstruction* HGraphBuilder::BuildLoadNamedGeneric(HValue* obj, |
| 3678 Property* expr) { | 3576 Property* expr) { |
| 3679 ASSERT(expr->key()->IsPropertyName()); | 3577 ASSERT(expr->key()->IsPropertyName()); |
| 3680 Handle<Object> name = expr->key()->AsLiteral()->handle(); | 3578 Handle<Object> name = expr->key()->AsLiteral()->handle(); |
| 3681 return new HLoadNamedGeneric(obj, name); | 3579 HContext* context = new HContext; |
| 3580 AddInstruction(context); |
| 3581 return new HLoadNamedGeneric(context, obj, name); |
| 3682 } | 3582 } |
| 3683 | 3583 |
| 3684 | 3584 |
| 3685 HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj, | 3585 HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj, |
| 3686 Property* expr, | 3586 Property* expr, |
| 3687 Handle<Map> map, | 3587 Handle<Map> map, |
| 3688 Handle<String> name) { | 3588 Handle<String> name) { |
| 3689 LookupResult lookup; | 3589 LookupResult lookup; |
| 3690 map->LookupInDescriptors(NULL, *name, &lookup); | 3590 map->LookupInDescriptors(NULL, *name, &lookup); |
| 3691 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3591 if (lookup.IsProperty() && lookup.type() == FIELD) { |
| 3692 return BuildLoadNamedField(obj, | 3592 return BuildLoadNamedField(obj, |
| 3693 expr, | 3593 expr, |
| 3694 map, | 3594 map, |
| 3695 &lookup, | 3595 &lookup, |
| 3696 true); | 3596 true); |
| 3697 } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) { | 3597 } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) { |
| 3698 AddInstruction(new HCheckNonSmi(obj)); | 3598 AddInstruction(new HCheckNonSmi(obj)); |
| 3699 AddInstruction(new HCheckMap(obj, map)); | 3599 AddInstruction(new HCheckMap(obj, map)); |
| 3700 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map)); | 3600 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map)); |
| 3701 return new HConstant(function, Representation::Tagged()); | 3601 return new HConstant(function, Representation::Tagged()); |
| 3702 } else { | 3602 } else { |
| 3703 return BuildLoadNamedGeneric(obj, expr); | 3603 return BuildLoadNamedGeneric(obj, expr); |
| 3704 } | 3604 } |
| 3705 } | 3605 } |
| 3706 | 3606 |
| 3707 | 3607 |
| 3708 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, | 3608 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
| 3709 HValue* key) { | 3609 HValue* key) { |
| 3710 return new HLoadKeyedGeneric(object, key); | 3610 HContext* context = new HContext; |
| 3611 AddInstruction(context); |
| 3612 return new HLoadKeyedGeneric(context, object, key); |
| 3711 } | 3613 } |
| 3712 | 3614 |
| 3713 | 3615 |
| 3714 HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, | 3616 HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, |
| 3715 HValue* key, | 3617 HValue* key, |
| 3716 Property* expr) { | 3618 Property* expr) { |
| 3717 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); | 3619 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); |
| 3718 AddInstruction(new HCheckNonSmi(object)); | 3620 AddInstruction(new HCheckNonSmi(object)); |
| 3719 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3621 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 3720 ASSERT(map->has_fast_elements()); | 3622 ASSERT(map->has_fast_elements()); |
| 3721 AddInstruction(new HCheckMap(object, map)); | 3623 AddInstruction(new HCheckMap(object, map)); |
| 3722 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); | 3624 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); |
| 3723 HLoadElements* elements = new HLoadElements(object); | 3625 HLoadElements* elements = new HLoadElements(object); |
| 3724 HInstruction* length = NULL; | 3626 HInstruction* length = NULL; |
| 3725 if (is_array) { | 3627 if (is_array) { |
| 3726 length = AddInstruction(new HJSArrayLength(object)); | 3628 length = AddInstruction(new HJSArrayLength(object)); |
| 3727 AddInstruction(new HBoundsCheck(key, length)); | 3629 AddInstruction(new HBoundsCheck(key, length)); |
| 3728 AddInstruction(elements); | 3630 AddInstruction(elements); |
| 3729 } else { | 3631 } else { |
| 3730 AddInstruction(elements); | 3632 AddInstruction(elements); |
| 3731 length = AddInstruction(new HFixedArrayLength(elements)); | 3633 length = AddInstruction(new HFixedArrayLength(elements)); |
| 3732 AddInstruction(new HBoundsCheck(key, length)); | 3634 AddInstruction(new HBoundsCheck(key, length)); |
| 3733 } | 3635 } |
| 3734 return new HLoadKeyedFastElement(elements, key); | 3636 return new HLoadKeyedFastElement(elements, key); |
| 3735 } | 3637 } |
| 3736 | 3638 |
| 3737 | 3639 |
| 3640 HInstruction* HGraphBuilder::BuildLoadKeyedPixelArrayElement(HValue* object, |
| 3641 HValue* key, |
| 3642 Property* expr) { |
| 3643 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); |
| 3644 AddInstruction(new HCheckNonSmi(object)); |
| 3645 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 3646 ASSERT(!map->has_fast_elements()); |
| 3647 ASSERT(map->has_pixel_array_elements()); |
| 3648 AddInstruction(new HCheckMap(object, map)); |
| 3649 HLoadElements* elements = new HLoadElements(object); |
| 3650 AddInstruction(elements); |
| 3651 HInstruction* length = new HPixelArrayLength(elements); |
| 3652 AddInstruction(length); |
| 3653 AddInstruction(new HBoundsCheck(key, length)); |
| 3654 HLoadPixelArrayExternalPointer* external_elements = |
| 3655 new HLoadPixelArrayExternalPointer(elements); |
| 3656 AddInstruction(external_elements); |
| 3657 HLoadPixelArrayElement* pixel_array_value = |
| 3658 new HLoadPixelArrayElement(external_elements, key); |
| 3659 return pixel_array_value; |
| 3660 } |
| 3661 |
| 3662 |
| 3738 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, | 3663 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, |
| 3739 HValue* key, | 3664 HValue* key, |
| 3740 HValue* value) { | 3665 HValue* value) { |
| 3741 return new HStoreKeyedGeneric(object, key, value); | 3666 HContext* context = new HContext; |
| 3667 AddInstruction(context); |
| 3668 return new HStoreKeyedGeneric(context, object, key, value); |
| 3742 } | 3669 } |
| 3743 | 3670 |
| 3744 | 3671 |
| 3745 HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object, | 3672 HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object, |
| 3746 HValue* key, | 3673 HValue* key, |
| 3747 HValue* val, | 3674 HValue* val, |
| 3748 Expression* expr) { | 3675 Expression* expr) { |
| 3749 ASSERT(expr->IsMonomorphic()); | 3676 ASSERT(expr->IsMonomorphic()); |
| 3750 AddInstruction(new HCheckNonSmi(object)); | 3677 AddInstruction(new HCheckNonSmi(object)); |
| 3751 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3678 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 3752 ASSERT(map->has_fast_elements()); | 3679 ASSERT(map->has_fast_elements()); |
| 3753 AddInstruction(new HCheckMap(object, map)); | 3680 AddInstruction(new HCheckMap(object, map)); |
| 3754 HInstruction* elements = AddInstruction(new HLoadElements(object)); | 3681 HInstruction* elements = AddInstruction(new HLoadElements(object)); |
| 3755 AddInstruction(new HCheckMap(elements, FACTORY->fixed_array_map())); | 3682 AddInstruction(new HCheckMap(elements, FACTORY->fixed_array_map())); |
| 3756 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); | 3683 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); |
| 3757 HInstruction* length = NULL; | 3684 HInstruction* length = NULL; |
| 3758 if (is_array) { | 3685 if (is_array) { |
| 3759 length = AddInstruction(new HJSArrayLength(object)); | 3686 length = AddInstruction(new HJSArrayLength(object)); |
| 3760 } else { | 3687 } else { |
| 3761 length = AddInstruction(new HFixedArrayLength(elements)); | 3688 length = AddInstruction(new HFixedArrayLength(elements)); |
| 3762 } | 3689 } |
| 3763 AddInstruction(new HBoundsCheck(key, length)); | 3690 AddInstruction(new HBoundsCheck(key, length)); |
| 3764 return new HStoreKeyedFastElement(elements, key, val); | 3691 return new HStoreKeyedFastElement(elements, key, val); |
| 3765 } | 3692 } |
| 3766 | 3693 |
| 3767 | 3694 |
| 3695 HInstruction* HGraphBuilder::BuildStoreKeyedPixelArrayElement( |
| 3696 HValue* object, |
| 3697 HValue* key, |
| 3698 HValue* val, |
| 3699 Expression* expr) { |
| 3700 ASSERT(expr->IsMonomorphic()); |
| 3701 AddInstruction(new HCheckNonSmi(object)); |
| 3702 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 3703 ASSERT(!map->has_fast_elements()); |
| 3704 ASSERT(map->has_pixel_array_elements()); |
| 3705 AddInstruction(new HCheckMap(object, map)); |
| 3706 HLoadElements* elements = new HLoadElements(object); |
| 3707 AddInstruction(elements); |
| 3708 HInstruction* length = AddInstruction(new HPixelArrayLength(elements)); |
| 3709 AddInstruction(new HBoundsCheck(key, length)); |
| 3710 HLoadPixelArrayExternalPointer* external_elements = |
| 3711 new HLoadPixelArrayExternalPointer(elements); |
| 3712 AddInstruction(external_elements); |
| 3713 return new HStorePixelArrayElement(external_elements, key, val); |
| 3714 } |
| 3715 |
| 3716 |
| 3768 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { | 3717 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
| 3769 VariableProxy* proxy = expr->obj()->AsVariableProxy(); | 3718 VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
| 3770 if (proxy == NULL) return false; | 3719 if (proxy == NULL) return false; |
| 3771 if (!proxy->var()->IsStackAllocated()) return false; | 3720 if (!proxy->var()->IsStackAllocated()) return false; |
| 3772 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { | 3721 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { |
| 3773 return false; | 3722 return false; |
| 3774 } | 3723 } |
| 3775 | 3724 |
| 3776 HInstruction* result = NULL; | 3725 HInstruction* result = NULL; |
| 3777 if (expr->key()->IsPropertyName()) { | 3726 if (expr->key()->IsPropertyName()) { |
| 3778 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 3727 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 3779 if (!name->IsEqualTo(CStrVector("length"))) return false; | 3728 if (!name->IsEqualTo(CStrVector("length"))) return false; |
| 3780 HInstruction* elements = AddInstruction(new HArgumentsElements); | 3729 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 3781 result = new HArgumentsLength(elements); | 3730 result = new HArgumentsLength(elements); |
| 3782 } else { | 3731 } else { |
| 3732 Push(graph()->GetArgumentsObject()); |
| 3783 VisitForValue(expr->key()); | 3733 VisitForValue(expr->key()); |
| 3784 if (HasStackOverflow()) return false; | 3734 if (HasStackOverflow()) return false; |
| 3785 HValue* key = Pop(); | 3735 HValue* key = Pop(); |
| 3736 Drop(1); // Arguments object. |
| 3786 HInstruction* elements = AddInstruction(new HArgumentsElements); | 3737 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 3787 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); | 3738 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
| 3788 AddInstruction(new HBoundsCheck(key, length)); | 3739 AddInstruction(new HBoundsCheck(key, length)); |
| 3789 result = new HAccessArgumentsAt(elements, length, key); | 3740 result = new HAccessArgumentsAt(elements, length, key); |
| 3790 } | 3741 } |
| 3791 ast_context()->ReturnInstruction(result, expr->id()); | 3742 ast_context()->ReturnInstruction(result, expr->id()); |
| 3792 return true; | 3743 return true; |
| 3793 } | 3744 } |
| 3794 | 3745 |
| 3795 | 3746 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3835 } else { | 3786 } else { |
| 3836 instr = BuildLoadNamedGeneric(obj, expr); | 3787 instr = BuildLoadNamedGeneric(obj, expr); |
| 3837 } | 3788 } |
| 3838 | 3789 |
| 3839 } else { | 3790 } else { |
| 3840 VISIT_FOR_VALUE(expr->key()); | 3791 VISIT_FOR_VALUE(expr->key()); |
| 3841 | 3792 |
| 3842 HValue* key = Pop(); | 3793 HValue* key = Pop(); |
| 3843 HValue* obj = Pop(); | 3794 HValue* obj = Pop(); |
| 3844 | 3795 |
| 3845 bool is_fast_elements = expr->IsMonomorphic() && | 3796 if (expr->IsMonomorphic()) { |
| 3846 expr->GetMonomorphicReceiverType()->has_fast_elements(); | 3797 Handle<Map> receiver_type(expr->GetMonomorphicReceiverType()); |
| 3847 | 3798 // An object has either fast elements or pixel array elements, but never |
| 3848 instr = is_fast_elements | 3799 // both. Pixel array maps that are assigned to pixel array elements are |
| 3849 ? BuildLoadKeyedFastElement(obj, key, expr) | 3800 // always created with the fast elements flag cleared. |
| 3850 : BuildLoadKeyedGeneric(obj, key); | 3801 if (receiver_type->has_pixel_array_elements()) { |
| 3802 instr = BuildLoadKeyedPixelArrayElement(obj, key, expr); |
| 3803 } else if (receiver_type->has_fast_elements()) { |
| 3804 instr = BuildLoadKeyedFastElement(obj, key, expr); |
| 3805 } |
| 3806 } |
| 3807 if (instr == NULL) { |
| 3808 instr = BuildLoadKeyedGeneric(obj, key); |
| 3809 } |
| 3851 } | 3810 } |
| 3852 instr->set_position(expr->position()); | 3811 instr->set_position(expr->position()); |
| 3853 ast_context()->ReturnInstruction(instr, expr->id()); | 3812 ast_context()->ReturnInstruction(instr, expr->id()); |
| 3854 } | 3813 } |
| 3855 | 3814 |
| 3856 | 3815 |
| 3857 void HGraphBuilder::AddCheckConstantFunction(Call* expr, | 3816 void HGraphBuilder::AddCheckConstantFunction(Call* expr, |
| 3858 HValue* receiver, | 3817 HValue* receiver, |
| 3859 Handle<Map> receiver_map, | 3818 Handle<Map> receiver_map, |
| 3860 bool smi_and_map_check) { | 3819 bool smi_and_map_check) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3873 } | 3832 } |
| 3874 | 3833 |
| 3875 | 3834 |
| 3876 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, | 3835 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
| 3877 HValue* receiver, | 3836 HValue* receiver, |
| 3878 ZoneMapList* types, | 3837 ZoneMapList* types, |
| 3879 Handle<String> name) { | 3838 Handle<String> name) { |
| 3880 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 3839 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 3881 int number_of_types = Min(types->length(), kMaxCallPolymorphism); | 3840 int number_of_types = Min(types->length(), kMaxCallPolymorphism); |
| 3882 ZoneMapList maps(number_of_types); | 3841 ZoneMapList maps(number_of_types); |
| 3883 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); | 3842 ZoneList<HSubgraph*> subgraphs(number_of_types); |
| 3884 bool needs_generic = (types->length() > kMaxCallPolymorphism); | 3843 bool needs_generic = (types->length() > kMaxCallPolymorphism); |
| 3885 | 3844 |
| 3886 // Build subgraphs for each of the specific maps. | 3845 // Build subgraphs for each of the specific maps. |
| 3887 // | 3846 // |
| 3888 // TODO(ager): We should recognize when the prototype chains for different | 3847 // TODO(ager): We should recognize when the prototype chains for different |
| 3889 // maps are identical. In that case we can avoid repeatedly generating the | 3848 // maps are identical. In that case we can avoid repeatedly generating the |
| 3890 // same prototype map checks. | 3849 // same prototype map checks. |
| 3891 for (int i = 0; i < number_of_types; ++i) { | 3850 for (int i = 0; i < number_of_types; ++i) { |
| 3892 Handle<Map> map = types->at(i); | 3851 Handle<Map> map = types->at(i); |
| 3893 if (expr->ComputeTarget(map, name)) { | 3852 if (expr->ComputeTarget(map, name)) { |
| 3894 maps.Add(map); | |
| 3895 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3853 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3896 SubgraphScope scope(this, subgraph); | 3854 SubgraphScope scope(this, subgraph); |
| 3897 AddCheckConstantFunction(expr, receiver, map, false); | 3855 AddCheckConstantFunction(expr, receiver, map, false); |
| 3898 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 3856 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
| 3899 PrintF("Trying to inline the polymorphic call to %s\n", | 3857 PrintF("Trying to inline the polymorphic call to %s\n", |
| 3900 *name->ToCString()); | 3858 *name->ToCString()); |
| 3901 } | 3859 } |
| 3902 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { | 3860 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { |
| 3903 // Check for bailout, as trying to inline might fail due to bailout | 3861 // Check for bailout, as trying to inline might fail due to bailout |
| 3904 // during hydrogen processing. | 3862 // during hydrogen processing. |
| 3905 CHECK_BAILOUT; | 3863 CHECK_BAILOUT; |
| 3906 HCall* call = new HCallConstantFunction(expr->target(), argument_count); | 3864 HCallConstantFunction* call = |
| 3865 new HCallConstantFunction(expr->target(), argument_count); |
| 3907 call->set_position(expr->position()); | 3866 call->set_position(expr->position()); |
| 3908 ProcessCall(call); | 3867 PreProcessCall(call); |
| 3909 PushAndAdd(call); | 3868 PushAndAdd(call); |
| 3910 } | 3869 } |
| 3870 maps.Add(map); |
| 3911 subgraphs.Add(subgraph); | 3871 subgraphs.Add(subgraph); |
| 3912 } else { | 3872 } else { |
| 3913 needs_generic = true; | 3873 needs_generic = true; |
| 3914 } | 3874 } |
| 3915 } | 3875 } |
| 3916 | 3876 |
| 3917 // If we couldn't compute the target for any of the maps just perform an | 3877 // If we couldn't compute the target for any of the maps just perform an |
| 3918 // IC call. | 3878 // IC call. |
| 3919 if (maps.length() == 0) { | 3879 if (maps.length() == 0) { |
| 3920 HCall* call = new HCallNamed(name, argument_count); | 3880 HContext* context = new HContext; |
| 3881 AddInstruction(context); |
| 3882 HCallNamed* call = new HCallNamed(context, name, argument_count); |
| 3921 call->set_position(expr->position()); | 3883 call->set_position(expr->position()); |
| 3922 ProcessCall(call); | 3884 PreProcessCall(call); |
| 3923 ast_context()->ReturnInstruction(call, expr->id()); | 3885 ast_context()->ReturnInstruction(call, expr->id()); |
| 3924 } else { | 3886 } else { |
| 3925 // Build subgraph for generic call through IC. | 3887 // Build subgraph for generic call through IC. |
| 3926 { | 3888 HSubgraph* default_graph = CreateBranchSubgraph(environment()); |
| 3927 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3889 { SubgraphScope scope(this, default_graph); |
| 3928 SubgraphScope scope(this, subgraph); | |
| 3929 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3890 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
| 3930 subgraph->FinishExit(new HDeoptimize()); | 3891 default_graph->exit_block()->FinishExit(new HDeoptimize()); |
| 3892 default_graph->set_exit_block(NULL); |
| 3931 } else { | 3893 } else { |
| 3932 HCall* call = new HCallNamed(name, argument_count); | 3894 HContext* context = new HContext; |
| 3895 AddInstruction(context); |
| 3896 HCallNamed* call = new HCallNamed(context, name, argument_count); |
| 3933 call->set_position(expr->position()); | 3897 call->set_position(expr->position()); |
| 3934 ProcessCall(call); | 3898 PreProcessCall(call); |
| 3935 PushAndAdd(call); | 3899 PushAndAdd(call); |
| 3936 } | 3900 } |
| 3937 subgraphs.Add(subgraph); | |
| 3938 } | 3901 } |
| 3939 | 3902 |
| 3940 HBasicBlock* new_exit_block = | 3903 HBasicBlock* new_exit_block = |
| 3941 BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); | 3904 BuildTypeSwitch(receiver, &maps, &subgraphs, default_graph, expr->id()); |
| 3942 subgraph()->set_exit_block(new_exit_block); | 3905 set_current_block(new_exit_block); |
| 3943 // In an effect context, we did not materialized the value in the | 3906 // In an effect context, we did not materialized the value in the |
| 3944 // predecessor environments so there's no need to handle it here. | 3907 // predecessor environments so there's no need to handle it here. |
| 3945 if (new_exit_block != NULL && !ast_context()->IsEffect()) { | 3908 if (new_exit_block != NULL && !ast_context()->IsEffect()) { |
| 3946 ast_context()->ReturnValue(Pop()); | 3909 ast_context()->ReturnValue(Pop()); |
| 3947 } | 3910 } |
| 3948 } | 3911 } |
| 3949 } | 3912 } |
| 3950 | 3913 |
| 3951 | 3914 |
| 3952 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { | 3915 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3998 if (FLAG_trace_inlining) TraceInline(target, false); | 3961 if (FLAG_trace_inlining) TraceInline(target, false); |
| 3999 return false; | 3962 return false; |
| 4000 } | 3963 } |
| 4001 | 3964 |
| 4002 int count_before = AstNode::Count(); | 3965 int count_before = AstNode::Count(); |
| 4003 | 3966 |
| 4004 // Parse and allocate variables. | 3967 // Parse and allocate variables. |
| 4005 CompilationInfo inner_info(target); | 3968 CompilationInfo inner_info(target); |
| 4006 if (!ParserApi::Parse(&inner_info) || | 3969 if (!ParserApi::Parse(&inner_info) || |
| 4007 !Scope::Analyze(&inner_info)) { | 3970 !Scope::Analyze(&inner_info)) { |
| 3971 if (inner_info.isolate()->has_pending_exception()) { |
| 3972 SetStackOverflow(); |
| 3973 // Stop trying to optimize and inline this function. |
| 3974 target->shared()->set_optimization_disabled(true); |
| 3975 } |
| 4008 return false; | 3976 return false; |
| 4009 } | 3977 } |
| 3978 if (inner_info.scope()->num_heap_slots() > 0) return false; |
| 4010 FunctionLiteral* function = inner_info.function(); | 3979 FunctionLiteral* function = inner_info.function(); |
| 4011 | 3980 |
| 4012 // Count the number of AST nodes added by inlining this call. | 3981 // Count the number of AST nodes added by inlining this call. |
| 4013 int nodes_added = AstNode::Count() - count_before; | 3982 int nodes_added = AstNode::Count() - count_before; |
| 4014 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { | 3983 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { |
| 4015 if (FLAG_trace_inlining) TraceInline(target, false); | 3984 if (FLAG_trace_inlining) TraceInline(target, false); |
| 4016 return false; | 3985 return false; |
| 4017 } | 3986 } |
| 4018 | 3987 |
| 4019 // Check if we can handle all declarations in the inlined functions. | 3988 // Check if we can handle all declarations in the inlined functions. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 4039 | 4008 |
| 4040 // Generate the deoptimization data for the unoptimized version of | 4009 // Generate the deoptimization data for the unoptimized version of |
| 4041 // the target function if we don't already have it. | 4010 // the target function if we don't already have it. |
| 4042 if (!shared->has_deoptimization_support()) { | 4011 if (!shared->has_deoptimization_support()) { |
| 4043 // Note that we compile here using the same AST that we will use for | 4012 // Note that we compile here using the same AST that we will use for |
| 4044 // generating the optimized inline code. | 4013 // generating the optimized inline code. |
| 4045 inner_info.EnableDeoptimizationSupport(); | 4014 inner_info.EnableDeoptimizationSupport(); |
| 4046 if (!FullCodeGenerator::MakeCode(&inner_info)) return false; | 4015 if (!FullCodeGenerator::MakeCode(&inner_info)) return false; |
| 4047 shared->EnableDeoptimizationSupport(*inner_info.code()); | 4016 shared->EnableDeoptimizationSupport(*inner_info.code()); |
| 4048 Compiler::RecordFunctionCompilation( | 4017 Compiler::RecordFunctionCompilation( |
| 4049 Logger::FUNCTION_TAG, | 4018 Logger::FUNCTION_TAG, &inner_info, shared); |
| 4050 Handle<String>(shared->DebugName()), | |
| 4051 shared->start_position(), | |
| 4052 &inner_info); | |
| 4053 } | 4019 } |
| 4054 | 4020 |
| 4055 // Save the pending call context and type feedback oracle. Set up new ones | 4021 // Save the pending call context and type feedback oracle. Set up new ones |
| 4056 // for the inlined function. | 4022 // for the inlined function. |
| 4057 ASSERT(shared->has_deoptimization_support()); | 4023 ASSERT(shared->has_deoptimization_support()); |
| 4058 AstContext* saved_call_context = call_context(); | 4024 AstContext* saved_call_context = call_context(); |
| 4059 HBasicBlock* saved_function_return = function_return(); | 4025 HBasicBlock* saved_function_return = function_return(); |
| 4060 TypeFeedbackOracle* saved_oracle = oracle(); | 4026 TypeFeedbackOracle* saved_oracle = oracle(); |
| 4061 // On-stack replacement cannot target inlined functions. Since we don't | 4027 // On-stack replacement cannot target inlined functions. Since we don't |
| 4062 // use a separate CompilationInfo structure for the inlined function, we | 4028 // use a separate CompilationInfo structure for the inlined function, we |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4098 oracle_ = saved_oracle; | 4064 oracle_ = saved_oracle; |
| 4099 graph()->info()->SetOsrAstId(saved_osr_ast_id); | 4065 graph()->info()->SetOsrAstId(saved_osr_ast_id); |
| 4100 return false; | 4066 return false; |
| 4101 } | 4067 } |
| 4102 | 4068 |
| 4103 // Update inlined nodes count. | 4069 // Update inlined nodes count. |
| 4104 inlined_count_ += nodes_added; | 4070 inlined_count_ += nodes_added; |
| 4105 | 4071 |
| 4106 if (FLAG_trace_inlining) TraceInline(target, true); | 4072 if (FLAG_trace_inlining) TraceInline(target, true); |
| 4107 | 4073 |
| 4108 if (body->HasExit()) { | 4074 if (body->exit_block() != NULL) { |
| 4109 // Add a return of undefined if control can fall off the body. In a | 4075 // Add a return of undefined if control can fall off the body. In a |
| 4110 // test context, undefined is false. | 4076 // test context, undefined is false. |
| 4111 HValue* return_value = graph()->GetConstantUndefined(); | 4077 HValue* return_value = graph()->GetConstantUndefined(); |
| 4112 if (test_context == NULL) { | 4078 if (test_context == NULL) { |
| 4113 ASSERT(function_return_ != NULL); | 4079 ASSERT(function_return_ != NULL); |
| 4114 body->exit_block()->AddLeaveInlined(return_value, function_return_); | 4080 body->exit_block()->AddLeaveInlined(return_value, function_return_); |
| 4115 } else { | 4081 } else { |
| 4116 // The graph builder assumes control can reach both branches of a | 4082 // The graph builder assumes control can reach both branches of a |
| 4117 // test, so we materialize the undefined value and test it rather than | 4083 // test, so we materialize the undefined value and test it rather than |
| 4118 // simply jumping to the false target. | 4084 // simply jumping to the false target. |
| 4119 // | 4085 // |
| 4120 // TODO(3168478): refactor to avoid this. | 4086 // TODO(3168478): refactor to avoid this. |
| 4121 HBasicBlock* empty_true = graph()->CreateBasicBlock(); | 4087 HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
| 4122 HBasicBlock* empty_false = graph()->CreateBasicBlock(); | 4088 HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
| 4123 HTest* test = new HTest(return_value, empty_true, empty_false); | 4089 HTest* test = new HTest(return_value, empty_true, empty_false); |
| 4124 body->exit_block()->Finish(test); | 4090 body->exit_block()->Finish(test); |
| 4125 | 4091 |
| 4126 HValue* const no_return_value = NULL; | 4092 HValue* const no_return_value = NULL; |
| 4127 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); | 4093 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); |
| 4128 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); | 4094 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); |
| 4129 } | 4095 } |
| 4130 body->set_exit_block(NULL); | 4096 body->set_exit_block(NULL); |
| 4131 } | 4097 } |
| 4132 | 4098 |
| 4133 // Record the environment at the inlined function call. | 4099 // Record the environment at the inlined function call. |
| 4134 AddSimulate(expr->ReturnId()); | 4100 AddSimulate(expr->ReturnId()); |
| 4135 | 4101 |
| 4136 // Jump to the function entry (without re-recording the environment). | 4102 // Jump to the function entry (without re-recording the environment). |
| 4137 subgraph()->exit_block()->Finish(new HGoto(body->entry_block())); | 4103 current_block()->Finish(new HGoto(body->entry_block())); |
| 4138 | 4104 |
| 4139 // Fix up the function exits. | 4105 // Fix up the function exits. |
| 4140 if (test_context != NULL) { | 4106 if (test_context != NULL) { |
| 4141 HBasicBlock* if_true = test_context->if_true(); | 4107 HBasicBlock* if_true = test_context->if_true(); |
| 4142 HBasicBlock* if_false = test_context->if_false(); | 4108 HBasicBlock* if_false = test_context->if_false(); |
| 4143 if_true->SetJoinId(expr->id()); | 4109 if_true->SetJoinId(expr->id()); |
| 4144 if_false->SetJoinId(expr->id()); | 4110 if_false->SetJoinId(expr->id()); |
| 4145 ASSERT(ast_context() == test_context); | 4111 ASSERT(ast_context() == test_context); |
| 4146 delete test_context; // Destructor pops from expression context stack. | 4112 delete test_context; // Destructor pops from expression context stack. |
| 4147 | 4113 |
| 4148 // Forward to the real test context. | 4114 // Forward to the real test context. |
| 4149 HValue* const no_return_value = NULL; | 4115 HValue* const no_return_value = NULL; |
| 4150 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 4116 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
| 4151 if (true_target->IsInlineReturnTarget()) { | 4117 if (true_target->IsInlineReturnTarget()) { |
| 4152 if_true->AddLeaveInlined(no_return_value, true_target); | 4118 if_true->AddLeaveInlined(no_return_value, true_target); |
| 4153 } else { | 4119 } else { |
| 4154 if_true->Goto(true_target); | 4120 if_true->Goto(true_target); |
| 4155 } | 4121 } |
| 4156 | 4122 |
| 4157 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 4123 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
| 4158 if (false_target->IsInlineReturnTarget()) { | 4124 if (false_target->IsInlineReturnTarget()) { |
| 4159 if_false->AddLeaveInlined(no_return_value, false_target); | 4125 if_false->AddLeaveInlined(no_return_value, false_target); |
| 4160 } else { | 4126 } else { |
| 4161 if_false->Goto(false_target); | 4127 if_false->Goto(false_target); |
| 4162 } | 4128 } |
| 4163 | 4129 |
| 4164 // TODO(kmillikin): Come up with a better way to handle this. It is too | 4130 // TODO(kmillikin): Come up with a better way to handle this. It is too |
| 4165 // subtle. NULL here indicates that the enclosing context has no control | 4131 // subtle. NULL here indicates that the enclosing context has no control |
| 4166 // flow to handle. | 4132 // flow to handle. |
| 4167 subgraph()->set_exit_block(NULL); | 4133 set_current_block(NULL); |
| 4168 | 4134 |
| 4169 } else { | 4135 } else { |
| 4170 function_return_->SetJoinId(expr->id()); | 4136 function_return_->SetJoinId(expr->id()); |
| 4171 subgraph()->set_exit_block(function_return_); | 4137 set_current_block(function_return_); |
| 4172 } | 4138 } |
| 4173 | 4139 |
| 4174 call_context_ = saved_call_context; | 4140 call_context_ = saved_call_context; |
| 4175 function_return_ = saved_function_return; | 4141 function_return_ = saved_function_return; |
| 4176 oracle_ = saved_oracle; | 4142 oracle_ = saved_oracle; |
| 4177 graph()->info()->SetOsrAstId(saved_osr_ast_id); | 4143 graph()->info()->SetOsrAstId(saved_osr_ast_id); |
| 4178 | 4144 |
| 4179 return true; | 4145 return true; |
| 4180 } | 4146 } |
| 4181 | 4147 |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4323 static bool HasCustomCallGenerator(Handle<JSFunction> function) { | 4289 static bool HasCustomCallGenerator(Handle<JSFunction> function) { |
| 4324 SharedFunctionInfo* info = function->shared(); | 4290 SharedFunctionInfo* info = function->shared(); |
| 4325 return info->HasBuiltinFunctionId() && | 4291 return info->HasBuiltinFunctionId() && |
| 4326 CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id()); | 4292 CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id()); |
| 4327 } | 4293 } |
| 4328 | 4294 |
| 4329 | 4295 |
| 4330 void HGraphBuilder::VisitCall(Call* expr) { | 4296 void HGraphBuilder::VisitCall(Call* expr) { |
| 4331 Expression* callee = expr->expression(); | 4297 Expression* callee = expr->expression(); |
| 4332 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4298 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4333 HCall* call = NULL; | 4299 HInstruction* call = NULL; |
| 4334 | 4300 |
| 4335 Property* prop = callee->AsProperty(); | 4301 Property* prop = callee->AsProperty(); |
| 4336 if (prop != NULL) { | 4302 if (prop != NULL) { |
| 4337 if (!prop->key()->IsPropertyName()) { | 4303 if (!prop->key()->IsPropertyName()) { |
| 4338 // Keyed function call. | 4304 // Keyed function call. |
| 4339 VisitArgument(prop->obj()); | 4305 VISIT_FOR_VALUE(prop->obj()); |
| 4340 CHECK_BAILOUT; | |
| 4341 | 4306 |
| 4342 VISIT_FOR_VALUE(prop->key()); | 4307 VISIT_FOR_VALUE(prop->key()); |
| 4343 // Push receiver and key like the non-optimized code generator expects it. | 4308 // Push receiver and key like the non-optimized code generator expects it. |
| 4344 HValue* key = Pop(); | 4309 HValue* key = Pop(); |
| 4345 HValue* receiver = Pop(); | 4310 HValue* receiver = Pop(); |
| 4346 Push(key); | 4311 Push(key); |
| 4347 Push(receiver); | 4312 Push(receiver); |
| 4348 | 4313 |
| 4349 VisitArgumentList(expr->arguments()); | 4314 VisitExpressions(expr->arguments()); |
| 4350 CHECK_BAILOUT; | 4315 CHECK_BAILOUT; |
| 4351 | 4316 |
| 4352 call = new HCallKeyed(key, argument_count); | 4317 HContext* context = new HContext; |
| 4318 AddInstruction(context); |
| 4319 call = PreProcessCall(new HCallKeyed(context, key, argument_count)); |
| 4353 call->set_position(expr->position()); | 4320 call->set_position(expr->position()); |
| 4354 ProcessCall(call); | |
| 4355 Drop(1); // Key. | 4321 Drop(1); // Key. |
| 4356 ast_context()->ReturnInstruction(call, expr->id()); | 4322 ast_context()->ReturnInstruction(call, expr->id()); |
| 4357 return; | 4323 return; |
| 4358 } | 4324 } |
| 4359 | 4325 |
| 4360 // Named function call. | 4326 // Named function call. |
| 4361 expr->RecordTypeFeedback(oracle()); | 4327 expr->RecordTypeFeedback(oracle()); |
| 4362 | 4328 |
| 4363 if (TryCallApply(expr)) return; | 4329 if (TryCallApply(expr)) return; |
| 4364 CHECK_BAILOUT; | 4330 CHECK_BAILOUT; |
| 4365 | 4331 |
| 4366 HValue* receiver = VisitArgument(prop->obj()); | 4332 VISIT_FOR_VALUE(prop->obj()); |
| 4367 CHECK_BAILOUT; | 4333 VisitExpressions(expr->arguments()); |
| 4368 VisitArgumentList(expr->arguments()); | |
| 4369 CHECK_BAILOUT; | 4334 CHECK_BAILOUT; |
| 4370 | 4335 |
| 4371 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4336 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4372 | 4337 |
| 4373 expr->RecordTypeFeedback(oracle()); | 4338 expr->RecordTypeFeedback(oracle()); |
| 4374 ZoneMapList* types = expr->GetReceiverTypes(); | 4339 ZoneMapList* types = expr->GetReceiverTypes(); |
| 4375 | 4340 |
| 4341 HValue* receiver = |
| 4342 environment()->ExpressionStackAt(expr->arguments()->length()); |
| 4376 if (expr->IsMonomorphic()) { | 4343 if (expr->IsMonomorphic()) { |
| 4377 Handle<Map> receiver_map = | 4344 Handle<Map> receiver_map = |
| 4378 (types == NULL) ? Handle<Map>::null() : types->first(); | 4345 (types == NULL) ? Handle<Map>::null() : types->first(); |
| 4379 if (TryInlineBuiltinFunction(expr, | 4346 if (TryInlineBuiltinFunction(expr, |
| 4380 receiver, | 4347 receiver, |
| 4381 receiver_map, | 4348 receiver_map, |
| 4382 expr->check_type())) { | 4349 expr->check_type())) { |
| 4383 return; | 4350 return; |
| 4384 } | 4351 } |
| 4385 | 4352 |
| 4386 if (HasCustomCallGenerator(expr->target()) || | 4353 if (HasCustomCallGenerator(expr->target()) || |
| 4387 expr->check_type() != RECEIVER_MAP_CHECK) { | 4354 expr->check_type() != RECEIVER_MAP_CHECK) { |
| 4388 // When the target has a custom call IC generator, use the IC, | 4355 // When the target has a custom call IC generator, use the IC, |
| 4389 // because it is likely to generate better code. Also use the | 4356 // because it is likely to generate better code. Also use the |
| 4390 // IC when a primitive receiver check is required. | 4357 // IC when a primitive receiver check is required. |
| 4391 call = new HCallNamed(name, argument_count); | 4358 HContext* context = new HContext; |
| 4359 AddInstruction(context); |
| 4360 call = PreProcessCall(new HCallNamed(context, name, argument_count)); |
| 4392 } else { | 4361 } else { |
| 4393 AddCheckConstantFunction(expr, receiver, receiver_map, true); | 4362 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4394 | 4363 |
| 4395 if (TryInline(expr)) { | 4364 if (TryInline(expr)) { |
| 4396 if (subgraph()->HasExit()) { | 4365 if (current_block() != NULL) { |
| 4397 HValue* return_value = Pop(); | 4366 HValue* return_value = Pop(); |
| 4398 // If we inlined a function in a test context then we need to emit | 4367 // If we inlined a function in a test context then we need to emit |
| 4399 // a simulate here to shadow the ones at the end of the | 4368 // a simulate here to shadow the ones at the end of the |
| 4400 // predecessor blocks. Those environments contain the return | 4369 // predecessor blocks. Those environments contain the return |
| 4401 // value on top and do not correspond to any actual state of the | 4370 // value on top and do not correspond to any actual state of the |
| 4402 // unoptimized code. | 4371 // unoptimized code. |
| 4403 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | 4372 if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
| 4404 ast_context()->ReturnValue(return_value); | 4373 ast_context()->ReturnValue(return_value); |
| 4405 } | 4374 } |
| 4406 return; | 4375 return; |
| 4407 } else { | 4376 } else { |
| 4408 // Check for bailout, as the TryInline call in the if condition above | 4377 // Check for bailout, as the TryInline call in the if condition above |
| 4409 // might return false due to bailout during hydrogen processing. | 4378 // might return false due to bailout during hydrogen processing. |
| 4410 CHECK_BAILOUT; | 4379 CHECK_BAILOUT; |
| 4411 call = new HCallConstantFunction(expr->target(), argument_count); | 4380 call = PreProcessCall(new HCallConstantFunction(expr->target(), |
| 4381 argument_count)); |
| 4412 } | 4382 } |
| 4413 } | 4383 } |
| 4414 } else if (types != NULL && types->length() > 1) { | 4384 } else if (types != NULL && types->length() > 1) { |
| 4415 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | 4385 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
| 4416 HandlePolymorphicCallNamed(expr, receiver, types, name); | 4386 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 4417 return; | 4387 return; |
| 4418 | 4388 |
| 4419 } else { | 4389 } else { |
| 4420 call = new HCallNamed(name, argument_count); | 4390 HContext* context = new HContext; |
| 4391 AddInstruction(context); |
| 4392 call = PreProcessCall(new HCallNamed(context, name, argument_count)); |
| 4421 } | 4393 } |
| 4422 | 4394 |
| 4423 } else { | 4395 } else { |
| 4424 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4396 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 4425 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); | 4397 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); |
| 4426 | 4398 |
| 4427 if (!global_call) { | 4399 if (!global_call) { |
| 4428 ++argument_count; | 4400 ++argument_count; |
| 4429 VisitArgument(expr->expression()); | 4401 VISIT_FOR_VALUE(expr->expression()); |
| 4430 CHECK_BAILOUT; | |
| 4431 } | 4402 } |
| 4432 | 4403 |
| 4433 if (global_call) { | 4404 if (global_call) { |
| 4434 // If there is a global property cell for the name at compile time and | 4405 // If there is a global property cell for the name at compile time and |
| 4435 // access check is not enabled we assume that the function will not change | 4406 // access check is not enabled we assume that the function will not change |
| 4436 // and generate optimized code for calling the function. | 4407 // and generate optimized code for calling the function. |
| 4437 CompilationInfo* info = graph()->info(); | 4408 CompilationInfo* info = graph()->info(); |
| 4438 bool known_global_function = info->has_global_object() && | 4409 bool known_global_function = info->has_global_object() && |
| 4439 !info->global_object()->IsAccessCheckNeeded() && | 4410 !info->global_object()->IsAccessCheckNeeded() && |
| 4440 expr->ComputeGlobalTarget(Handle<GlobalObject>(info->global_object()), | 4411 expr->ComputeGlobalTarget(Handle<GlobalObject>(info->global_object()), |
| 4441 var->name()); | 4412 var->name()); |
| 4442 if (known_global_function) { | 4413 if (known_global_function) { |
| 4443 // Push the global object instead of the global receiver because | 4414 // Push the global object instead of the global receiver because |
| 4444 // code generated by the full code generator expects it. | 4415 // code generated by the full code generator expects it. |
| 4445 HContext* context = new HContext; | 4416 HContext* context = new HContext; |
| 4446 HGlobalObject* global_object = new HGlobalObject(context); | 4417 HGlobalObject* global_object = new HGlobalObject(context); |
| 4447 AddInstruction(context); | 4418 AddInstruction(context); |
| 4448 PushAndAdd(global_object); | 4419 PushAndAdd(global_object); |
| 4449 VisitArgumentList(expr->arguments()); | 4420 VisitExpressions(expr->arguments()); |
| 4450 CHECK_BAILOUT; | 4421 CHECK_BAILOUT; |
| 4451 | 4422 |
| 4452 VISIT_FOR_VALUE(expr->expression()); | 4423 VISIT_FOR_VALUE(expr->expression()); |
| 4453 HValue* function = Pop(); | 4424 HValue* function = Pop(); |
| 4454 AddInstruction(new HCheckFunction(function, expr->target())); | 4425 AddInstruction(new HCheckFunction(function, expr->target())); |
| 4455 | 4426 |
| 4456 // Replace the global object with the global receiver. | 4427 // Replace the global object with the global receiver. |
| 4457 HGlobalReceiver* global_receiver = new HGlobalReceiver(global_object); | 4428 HGlobalReceiver* global_receiver = new HGlobalReceiver(global_object); |
| 4458 // Index of the receiver from the top of the expression stack. | 4429 // Index of the receiver from the top of the expression stack. |
| 4459 const int receiver_index = argument_count - 1; | 4430 const int receiver_index = argument_count - 1; |
| 4460 AddInstruction(global_receiver); | 4431 AddInstruction(global_receiver); |
| 4461 ASSERT(environment()->ExpressionStackAt(receiver_index)-> | 4432 ASSERT(environment()->ExpressionStackAt(receiver_index)-> |
| 4462 IsGlobalObject()); | 4433 IsGlobalObject()); |
| 4463 environment()->SetExpressionStackAt(receiver_index, global_receiver); | 4434 environment()->SetExpressionStackAt(receiver_index, global_receiver); |
| 4464 | 4435 |
| 4465 if (TryInline(expr)) { | 4436 if (TryInline(expr)) { |
| 4466 if (subgraph()->HasExit()) { | 4437 if (current_block() != NULL) { |
| 4467 HValue* return_value = Pop(); | 4438 HValue* return_value = Pop(); |
| 4468 // If we inlined a function in a test context then we need to | 4439 // If we inlined a function in a test context then we need to |
| 4469 // emit a simulate here to shadow the ones at the end of the | 4440 // emit a simulate here to shadow the ones at the end of the |
| 4470 // predecessor blocks. Those environments contain the return | 4441 // predecessor blocks. Those environments contain the return |
| 4471 // value on top and do not correspond to any actual state of the | 4442 // value on top and do not correspond to any actual state of the |
| 4472 // unoptimized code. | 4443 // unoptimized code. |
| 4473 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | 4444 if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
| 4474 ast_context()->ReturnValue(return_value); | 4445 ast_context()->ReturnValue(return_value); |
| 4475 } | 4446 } |
| 4476 return; | 4447 return; |
| 4477 } | 4448 } |
| 4478 // Check for bailout, as trying to inline might fail due to bailout | 4449 // Check for bailout, as trying to inline might fail due to bailout |
| 4479 // during hydrogen processing. | 4450 // during hydrogen processing. |
| 4480 CHECK_BAILOUT; | 4451 CHECK_BAILOUT; |
| 4481 | 4452 |
| 4482 call = new HCallKnownGlobal(expr->target(), argument_count); | 4453 call = PreProcessCall(new HCallKnownGlobal(expr->target(), |
| 4454 argument_count)); |
| 4483 } else { | 4455 } else { |
| 4484 HContext* context = new HContext; | 4456 HContext* context = new HContext; |
| 4485 AddInstruction(context); | 4457 AddInstruction(context); |
| 4486 PushAndAdd(new HGlobalObject(context)); | 4458 PushAndAdd(new HGlobalObject(context)); |
| 4487 VisitArgumentList(expr->arguments()); | 4459 VisitExpressions(expr->arguments()); |
| 4488 CHECK_BAILOUT; | 4460 CHECK_BAILOUT; |
| 4489 | 4461 |
| 4490 call = new HCallGlobal(var->name(), argument_count); | 4462 call = PreProcessCall(new HCallGlobal(context, |
| 4463 var->name(), |
| 4464 argument_count)); |
| 4491 } | 4465 } |
| 4492 | 4466 |
| 4493 } else { | 4467 } else { |
| 4494 HContext* context = new HContext; | 4468 HContext* context = new HContext; |
| 4495 HGlobalObject* global_object = new HGlobalObject(context); | 4469 HGlobalObject* global_object = new HGlobalObject(context); |
| 4496 AddInstruction(context); | 4470 AddInstruction(context); |
| 4497 AddInstruction(global_object); | 4471 AddInstruction(global_object); |
| 4498 PushAndAdd(new HGlobalReceiver(global_object)); | 4472 PushAndAdd(new HGlobalReceiver(global_object)); |
| 4499 VisitArgumentList(expr->arguments()); | 4473 VisitExpressions(expr->arguments()); |
| 4500 CHECK_BAILOUT; | 4474 CHECK_BAILOUT; |
| 4501 | 4475 |
| 4502 call = new HCallFunction(argument_count); | 4476 call = PreProcessCall(new HCallFunction(context, argument_count)); |
| 4503 } | 4477 } |
| 4504 } | 4478 } |
| 4505 | 4479 |
| 4506 call->set_position(expr->position()); | 4480 call->set_position(expr->position()); |
| 4507 ProcessCall(call); | |
| 4508 ast_context()->ReturnInstruction(call, expr->id()); | 4481 ast_context()->ReturnInstruction(call, expr->id()); |
| 4509 } | 4482 } |
| 4510 | 4483 |
| 4511 | 4484 |
| 4512 void HGraphBuilder::VisitCallNew(CallNew* expr) { | 4485 void HGraphBuilder::VisitCallNew(CallNew* expr) { |
| 4513 // The constructor function is also used as the receiver argument to the | 4486 // The constructor function is also used as the receiver argument to the |
| 4514 // JS construct call builtin. | 4487 // JS construct call builtin. |
| 4515 VisitArgument(expr->expression()); | 4488 VISIT_FOR_VALUE(expr->expression()); |
| 4516 CHECK_BAILOUT; | 4489 VisitExpressions(expr->arguments()); |
| 4517 VisitArgumentList(expr->arguments()); | |
| 4518 CHECK_BAILOUT; | 4490 CHECK_BAILOUT; |
| 4519 | 4491 |
| 4520 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 4492 HContext* context = new HContext; |
| 4521 HCall* call = new HCallNew(argument_count); | 4493 AddInstruction(context); |
| 4494 |
| 4495 // The constructor is both an operand to the instruction and an argument |
| 4496 // to the construct call. |
| 4497 int arg_count = expr->arguments()->length() + 1; // Plus constructor. |
| 4498 HValue* constructor = environment()->ExpressionStackAt(arg_count - 1); |
| 4499 HCallNew* call = new HCallNew(context, constructor, arg_count); |
| 4522 call->set_position(expr->position()); | 4500 call->set_position(expr->position()); |
| 4523 ProcessCall(call); | 4501 PreProcessCall(call); |
| 4524 ast_context()->ReturnInstruction(call, expr->id()); | 4502 ast_context()->ReturnInstruction(call, expr->id()); |
| 4525 } | 4503 } |
| 4526 | 4504 |
| 4527 | 4505 |
| 4528 // Support for generating inlined runtime functions. | 4506 // Support for generating inlined runtime functions. |
| 4529 | 4507 |
| 4530 // Lookup table for generators for runtime calls that are generated inline. | 4508 // Lookup table for generators for runtime calls that are generated inline. |
| 4531 // Elements of the table are member pointers to functions of HGraphBuilder. | 4509 // Elements of the table are member pointers to functions of HGraphBuilder. |
| 4532 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ | 4510 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ |
| 4533 &HGraphBuilder::Generate##Name, | 4511 &HGraphBuilder::Generate##Name, |
| 4534 | 4512 |
| 4535 const HGraphBuilder::InlineFunctionGenerator | 4513 const HGraphBuilder::InlineFunctionGenerator |
| 4536 HGraphBuilder::kInlineFunctionGenerators[] = { | 4514 HGraphBuilder::kInlineFunctionGenerators[] = { |
| 4537 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) | 4515 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) |
| 4538 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) | 4516 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) |
| 4539 }; | 4517 }; |
| 4540 #undef INLINE_FUNCTION_GENERATOR_ADDRESS | 4518 #undef INLINE_FUNCTION_GENERATOR_ADDRESS |
| 4541 | 4519 |
| 4542 | 4520 |
| 4543 void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { | 4521 void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { |
| 4544 Handle<String> name = expr->name(); | 4522 if (expr->is_jsruntime()) { |
| 4545 if (name->IsEqualTo(CStrVector("_Log"))) { | 4523 BAILOUT("call to a JavaScript runtime function"); |
| 4546 ast_context()->ReturnValue(graph()->GetConstantUndefined()); | |
| 4547 return; | |
| 4548 } | 4524 } |
| 4549 | 4525 |
| 4550 const Runtime::Function* function = expr->function(); | 4526 const Runtime::Function* function = expr->function(); |
| 4551 if (expr->is_jsruntime()) { | |
| 4552 BAILOUT("call to a JavaScript runtime function"); | |
| 4553 } | |
| 4554 ASSERT(function != NULL); | 4527 ASSERT(function != NULL); |
| 4555 | |
| 4556 VisitArgumentList(expr->arguments()); | |
| 4557 CHECK_BAILOUT; | |
| 4558 | |
| 4559 int argument_count = expr->arguments()->length(); | |
| 4560 if (function->intrinsic_type == Runtime::INLINE) { | 4528 if (function->intrinsic_type == Runtime::INLINE) { |
| 4561 ASSERT(name->length() > 0); | 4529 ASSERT(expr->name()->length() > 0); |
| 4562 ASSERT(name->Get(0) == '_'); | 4530 ASSERT(expr->name()->Get(0) == '_'); |
| 4563 // Call to an inline function. | 4531 // Call to an inline function. |
| 4564 int lookup_index = static_cast<int>(function->function_id) - | 4532 int lookup_index = static_cast<int>(function->function_id) - |
| 4565 static_cast<int>(Runtime::kFirstInlineFunction); | 4533 static_cast<int>(Runtime::kFirstInlineFunction); |
| 4566 ASSERT(lookup_index >= 0); | 4534 ASSERT(lookup_index >= 0); |
| 4567 ASSERT(static_cast<size_t>(lookup_index) < | 4535 ASSERT(static_cast<size_t>(lookup_index) < |
| 4568 ARRAY_SIZE(kInlineFunctionGenerators)); | 4536 ARRAY_SIZE(kInlineFunctionGenerators)); |
| 4569 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; | 4537 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; |
| 4570 | 4538 |
| 4571 // Call the inline code generator using the pointer-to-member. | 4539 // Call the inline code generator using the pointer-to-member. |
| 4572 (this->*generator)(argument_count, expr->id()); | 4540 (this->*generator)(expr); |
| 4573 } else { | 4541 } else { |
| 4574 ASSERT(function->intrinsic_type == Runtime::RUNTIME); | 4542 ASSERT(function->intrinsic_type == Runtime::RUNTIME); |
| 4575 HCall* call = new HCallRuntime(name, expr->function(), argument_count); | 4543 VisitArgumentList(expr->arguments()); |
| 4544 CHECK_BAILOUT; |
| 4545 |
| 4546 Handle<String> name = expr->name(); |
| 4547 int argument_count = expr->arguments()->length(); |
| 4548 HCallRuntime* call = new HCallRuntime(name, function, argument_count); |
| 4576 call->set_position(RelocInfo::kNoPosition); | 4549 call->set_position(RelocInfo::kNoPosition); |
| 4577 ProcessCall(call); | 4550 Drop(argument_count); |
| 4578 ast_context()->ReturnInstruction(call, expr->id()); | 4551 ast_context()->ReturnInstruction(call, expr->id()); |
| 4579 } | 4552 } |
| 4580 } | 4553 } |
| 4581 | 4554 |
| 4582 | 4555 |
| 4583 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { | 4556 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
| 4584 Token::Value op = expr->op(); | 4557 Token::Value op = expr->op(); |
| 4585 if (op == Token::VOID) { | 4558 if (op == Token::VOID) { |
| 4586 VISIT_FOR_EFFECT(expr->expression()); | 4559 VISIT_FOR_EFFECT(expr->expression()); |
| 4587 ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 4560 ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 4588 } else if (op == Token::DELETE) { | 4561 } else if (op == Token::DELETE) { |
| 4589 Property* prop = expr->expression()->AsProperty(); | 4562 Property* prop = expr->expression()->AsProperty(); |
| 4590 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4563 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 4591 if (prop == NULL && var == NULL) { | 4564 if (prop == NULL && var == NULL) { |
| 4592 // Result of deleting non-property, non-variable reference is true. | 4565 // Result of deleting non-property, non-variable reference is true. |
| 4593 // Evaluate the subexpression for side effects. | 4566 // Evaluate the subexpression for side effects. |
| 4594 VISIT_FOR_EFFECT(expr->expression()); | 4567 VISIT_FOR_EFFECT(expr->expression()); |
| 4595 ast_context()->ReturnValue(graph()->GetConstantTrue()); | 4568 ast_context()->ReturnValue(graph()->GetConstantTrue()); |
| 4596 } else if (var != NULL && | 4569 } else if (var != NULL && |
| 4597 !var->is_global() && | 4570 !var->is_global() && |
| 4598 var->AsSlot() != NULL && | 4571 var->AsSlot() != NULL && |
| 4599 var->AsSlot()->type() != Slot::LOOKUP) { | 4572 var->AsSlot()->type() != Slot::LOOKUP) { |
| 4600 // Result of deleting non-global, non-dynamic variables is false. | 4573 // Result of deleting non-global, non-dynamic variables is false. |
| 4601 // The subexpression does not have side effects. | 4574 // The subexpression does not have side effects. |
| 4602 ast_context()->ReturnValue(graph()->GetConstantFalse()); | 4575 ast_context()->ReturnValue(graph()->GetConstantFalse()); |
| 4603 } else if (prop != NULL) { | 4576 } else if (prop != NULL) { |
| 4604 VISIT_FOR_VALUE(prop->obj()); | 4577 if (prop->is_synthetic()) { |
| 4605 VISIT_FOR_VALUE(prop->key()); | 4578 // Result of deleting parameters is false, even when they rewrite |
| 4606 HValue* key = Pop(); | 4579 // to accesses on the arguments object. |
| 4607 HValue* obj = Pop(); | 4580 ast_context()->ReturnValue(graph()->GetConstantFalse()); |
| 4608 ast_context()->ReturnInstruction(new HDeleteProperty(obj, key), | 4581 } else { |
| 4609 expr->id()); | 4582 VISIT_FOR_VALUE(prop->obj()); |
| 4583 VISIT_FOR_VALUE(prop->key()); |
| 4584 HValue* key = Pop(); |
| 4585 HValue* obj = Pop(); |
| 4586 HDeleteProperty* instr = new HDeleteProperty(obj, key); |
| 4587 ast_context()->ReturnInstruction(instr, expr->id()); |
| 4588 } |
| 4610 } else if (var->is_global()) { | 4589 } else if (var->is_global()) { |
| 4611 BAILOUT("delete with global variable"); | 4590 BAILOUT("delete with global variable"); |
| 4612 } else { | 4591 } else { |
| 4613 BAILOUT("delete with non-global variable"); | 4592 BAILOUT("delete with non-global variable"); |
| 4614 } | 4593 } |
| 4615 } else if (op == Token::NOT) { | 4594 } else if (op == Token::NOT) { |
| 4616 if (ast_context()->IsTest()) { | 4595 if (ast_context()->IsTest()) { |
| 4617 TestContext* context = TestContext::cast(ast_context()); | 4596 TestContext* context = TestContext::cast(ast_context()); |
| 4618 VisitForControl(expr->expression(), | 4597 VisitForControl(expr->expression(), |
| 4619 context->if_false(), | 4598 context->if_false(), |
| 4620 context->if_true()); | 4599 context->if_true()); |
| 4600 } else if (ast_context()->IsValue()) { |
| 4601 HBasicBlock* materialize_false = graph()->CreateBasicBlock(); |
| 4602 HBasicBlock* materialize_true = graph()->CreateBasicBlock(); |
| 4603 VISIT_FOR_CONTROL(expr->expression(), |
| 4604 materialize_false, |
| 4605 materialize_true); |
| 4606 materialize_false->SetJoinId(expr->expression()->id()); |
| 4607 materialize_true->SetJoinId(expr->expression()->id()); |
| 4608 |
| 4609 set_current_block(materialize_false); |
| 4610 Push(graph()->GetConstantFalse()); |
| 4611 set_current_block(materialize_true); |
| 4612 Push(graph()->GetConstantTrue()); |
| 4613 |
| 4614 HBasicBlock* join = |
| 4615 CreateJoin(materialize_false, materialize_true, expr->id()); |
| 4616 set_current_block(join); |
| 4617 ast_context()->ReturnValue(Pop()); |
| 4621 } else { | 4618 } else { |
| 4622 HSubgraph* true_graph = CreateEmptySubgraph(); | 4619 ASSERT(ast_context()->IsEffect()); |
| 4623 HSubgraph* false_graph = CreateEmptySubgraph(); | 4620 VisitForEffect(expr->expression()); |
| 4624 VISIT_FOR_CONTROL(expr->expression(), | 4621 } |
| 4625 false_graph->entry_block(), | |
| 4626 true_graph->entry_block()); | |
| 4627 true_graph->entry_block()->SetJoinId(expr->expression()->id()); | |
| 4628 true_graph->environment()->Push(graph_->GetConstantTrue()); | |
| 4629 | 4622 |
| 4630 false_graph->entry_block()->SetJoinId(expr->expression()->id()); | |
| 4631 false_graph->environment()->Push(graph_->GetConstantFalse()); | |
| 4632 | |
| 4633 current_subgraph_->AppendJoin(true_graph, false_graph, expr); | |
| 4634 ast_context()->ReturnValue(Pop()); | |
| 4635 } | |
| 4636 } else if (op == Token::BIT_NOT || op == Token::SUB) { | 4623 } else if (op == Token::BIT_NOT || op == Token::SUB) { |
| 4637 VISIT_FOR_VALUE(expr->expression()); | 4624 VISIT_FOR_VALUE(expr->expression()); |
| 4638 HValue* value = Pop(); | 4625 HValue* value = Pop(); |
| 4639 HInstruction* instr = NULL; | 4626 HInstruction* instr = NULL; |
| 4640 switch (op) { | 4627 switch (op) { |
| 4641 case Token::BIT_NOT: | 4628 case Token::BIT_NOT: |
| 4642 instr = new HBitNot(value); | 4629 instr = new HBitNot(value); |
| 4643 break; | 4630 break; |
| 4644 case Token::SUB: | 4631 case Token::SUB: |
| 4645 instr = new HMul(graph_->GetConstantMinus1(), value); | 4632 instr = new HMul(graph_->GetConstantMinus1(), value); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4679 void HGraphBuilder::VisitCountOperation(CountOperation* expr) { | 4666 void HGraphBuilder::VisitCountOperation(CountOperation* expr) { |
| 4680 IncrementOperation* increment = expr->increment(); | 4667 IncrementOperation* increment = expr->increment(); |
| 4681 Expression* target = increment->expression(); | 4668 Expression* target = increment->expression(); |
| 4682 VariableProxy* proxy = target->AsVariableProxy(); | 4669 VariableProxy* proxy = target->AsVariableProxy(); |
| 4683 Variable* var = proxy->AsVariable(); | 4670 Variable* var = proxy->AsVariable(); |
| 4684 Property* prop = target->AsProperty(); | 4671 Property* prop = target->AsProperty(); |
| 4685 ASSERT(var == NULL || prop == NULL); | 4672 ASSERT(var == NULL || prop == NULL); |
| 4686 bool inc = expr->op() == Token::INC; | 4673 bool inc = expr->op() == Token::INC; |
| 4687 | 4674 |
| 4688 if (var != NULL) { | 4675 if (var != NULL) { |
| 4689 if (!var->is_global() && !var->IsStackAllocated()) { | |
| 4690 BAILOUT("non-stack/non-global variable in count operation"); | |
| 4691 } | |
| 4692 | |
| 4693 VISIT_FOR_VALUE(target); | 4676 VISIT_FOR_VALUE(target); |
| 4694 | 4677 |
| 4695 // Match the full code generator stack by simulating an extra stack | 4678 // Match the full code generator stack by simulating an extra stack |
| 4696 // element for postfix operations in a non-effect context. | 4679 // element for postfix operations in a non-effect context. |
| 4697 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); | 4680 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); |
| 4698 HValue* before = has_extra ? Top() : Pop(); | 4681 HValue* before = has_extra ? Top() : Pop(); |
| 4699 HInstruction* after = BuildIncrement(before, inc); | 4682 HInstruction* after = BuildIncrement(before, inc); |
| 4700 AddInstruction(after); | 4683 AddInstruction(after); |
| 4701 Push(after); | 4684 Push(after); |
| 4702 | 4685 |
| 4703 if (var->is_global()) { | 4686 if (var->is_global()) { |
| 4704 HandleGlobalVariableAssignment(var, | 4687 HandleGlobalVariableAssignment(var, |
| 4705 after, | 4688 after, |
| 4706 expr->position(), | 4689 expr->position(), |
| 4707 expr->AssignmentId()); | 4690 expr->AssignmentId()); |
| 4691 } else if (var->IsStackAllocated()) { |
| 4692 Bind(var, after); |
| 4693 } else if (var->IsContextSlot()) { |
| 4694 HValue* context = BuildContextChainWalk(var); |
| 4695 int index = var->AsSlot()->index(); |
| 4696 HStoreContextSlot* instr = new HStoreContextSlot(context, index, after); |
| 4697 AddInstruction(instr); |
| 4698 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 4708 } else { | 4699 } else { |
| 4709 ASSERT(var->IsStackAllocated()); | 4700 BAILOUT("lookup variable in count operation"); |
| 4710 Bind(var, after); | |
| 4711 } | 4701 } |
| 4712 Drop(has_extra ? 2 : 1); | 4702 Drop(has_extra ? 2 : 1); |
| 4713 ast_context()->ReturnValue(expr->is_postfix() ? before : after); | 4703 ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
| 4714 | 4704 |
| 4715 } else if (prop != NULL) { | 4705 } else if (prop != NULL) { |
| 4716 prop->RecordTypeFeedback(oracle()); | 4706 prop->RecordTypeFeedback(oracle()); |
| 4717 | 4707 |
| 4718 if (prop->key()->IsPropertyName()) { | 4708 if (prop->key()->IsPropertyName()) { |
| 4719 // Named property. | 4709 // Named property. |
| 4720 | 4710 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4779 if (load->HasSideEffects()) AddSimulate(increment->id()); | 4769 if (load->HasSideEffects()) AddSimulate(increment->id()); |
| 4780 | 4770 |
| 4781 HValue* before = Pop(); | 4771 HValue* before = Pop(); |
| 4782 // There is no deoptimization to after the increment, so we don't need | 4772 // There is no deoptimization to after the increment, so we don't need |
| 4783 // to simulate the expression stack after this instruction. | 4773 // to simulate the expression stack after this instruction. |
| 4784 HInstruction* after = BuildIncrement(before, inc); | 4774 HInstruction* after = BuildIncrement(before, inc); |
| 4785 AddInstruction(after); | 4775 AddInstruction(after); |
| 4786 | 4776 |
| 4787 HInstruction* store = is_fast_elements | 4777 HInstruction* store = is_fast_elements |
| 4788 ? BuildStoreKeyedFastElement(obj, key, after, prop) | 4778 ? BuildStoreKeyedFastElement(obj, key, after, prop) |
| 4789 : new HStoreKeyedGeneric(obj, key, after); | 4779 : BuildStoreKeyedGeneric(obj, key, after); |
| 4790 AddInstruction(store); | 4780 AddInstruction(store); |
| 4791 | 4781 |
| 4792 // Drop the key from the bailout environment. Overwrite the receiver | 4782 // Drop the key from the bailout environment. Overwrite the receiver |
| 4793 // with the result of the operation, and the placeholder with the | 4783 // with the result of the operation, and the placeholder with the |
| 4794 // original value if necessary. | 4784 // original value if necessary. |
| 4795 Drop(1); | 4785 Drop(1); |
| 4796 environment()->SetExpressionStackAt(0, after); | 4786 environment()->SetExpressionStackAt(0, after); |
| 4797 if (has_extra) environment()->SetExpressionStackAt(1, before); | 4787 if (has_extra) environment()->SetExpressionStackAt(1, before); |
| 4798 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 4788 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 4799 Drop(has_extra ? 2 : 1); | 4789 Drop(has_extra ? 2 : 1); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4911 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | 4901 HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
| 4912 if (is_logical_and) { | 4902 if (is_logical_and) { |
| 4913 VISIT_FOR_CONTROL(expr->left(), eval_right, context->if_false()); | 4903 VISIT_FOR_CONTROL(expr->left(), eval_right, context->if_false()); |
| 4914 } else { | 4904 } else { |
| 4915 VISIT_FOR_CONTROL(expr->left(), context->if_true(), eval_right); | 4905 VISIT_FOR_CONTROL(expr->left(), context->if_true(), eval_right); |
| 4916 } | 4906 } |
| 4917 eval_right->SetJoinId(expr->RightId()); | 4907 eval_right->SetJoinId(expr->RightId()); |
| 4918 | 4908 |
| 4919 // Translate right subexpression by visiting it in the same AST | 4909 // Translate right subexpression by visiting it in the same AST |
| 4920 // context as the entire expression. | 4910 // context as the entire expression. |
| 4921 subgraph()->set_exit_block(eval_right); | 4911 set_current_block(eval_right); |
| 4922 Visit(expr->right()); | 4912 Visit(expr->right()); |
| 4923 | 4913 |
| 4924 } else { | 4914 } else if (ast_context()->IsValue()) { |
| 4925 VISIT_FOR_VALUE(expr->left()); | 4915 VISIT_FOR_VALUE(expr->left()); |
| 4926 ASSERT(current_subgraph_->HasExit()); | 4916 ASSERT(current_block() != NULL); |
| 4927 | 4917 |
| 4928 HValue* left = Top(); | 4918 HValue* left = Top(); |
| 4929 HEnvironment* environment_copy = environment()->Copy(); | 4919 HEnvironment* environment_copy = environment()->Copy(); |
| 4930 environment_copy->Pop(); | 4920 environment_copy->Pop(); |
| 4931 HSubgraph* right_subgraph; | 4921 HSubgraph* right_subgraph; |
| 4932 right_subgraph = CreateBranchSubgraph(environment_copy); | 4922 right_subgraph = CreateBranchSubgraph(environment_copy); |
| 4933 ADD_TO_SUBGRAPH(right_subgraph, expr->right()); | 4923 ADD_TO_SUBGRAPH(right_subgraph, expr->right()); |
| 4934 current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left); | 4924 |
| 4935 current_subgraph_->exit_block()->SetJoinId(expr->id()); | 4925 ASSERT(current_block() != NULL && |
| 4926 right_subgraph->exit_block() != NULL); |
| 4927 // We need an extra block to maintain edge-split form. |
| 4928 HBasicBlock* empty_block = graph()->CreateBasicBlock(); |
| 4929 HBasicBlock* join_block = graph()->CreateBasicBlock(); |
| 4930 |
| 4931 HTest* test = is_logical_and |
| 4932 ? new HTest(left, right_subgraph->entry_block(), empty_block) |
| 4933 : new HTest(left, empty_block, right_subgraph->entry_block()); |
| 4934 current_block()->Finish(test); |
| 4935 empty_block->Goto(join_block); |
| 4936 right_subgraph->exit_block()->Goto(join_block); |
| 4937 join_block->SetJoinId(expr->id()); |
| 4938 set_current_block(join_block); |
| 4936 ast_context()->ReturnValue(Pop()); | 4939 ast_context()->ReturnValue(Pop()); |
| 4940 } else { |
| 4941 ASSERT(ast_context()->IsEffect()); |
| 4942 // In an effect context, we don't need the value of the left |
| 4943 // subexpression, only its control flow and side effects. We need an |
| 4944 // extra block to maintain edge-split form. |
| 4945 HBasicBlock* empty_block = graph()->CreateBasicBlock(); |
| 4946 HBasicBlock* right_block = graph()->CreateBasicBlock(); |
| 4947 HBasicBlock* join_block = graph()->CreateBasicBlock(); |
| 4948 if (is_logical_and) { |
| 4949 VISIT_FOR_CONTROL(expr->left(), right_block, empty_block); |
| 4950 } else { |
| 4951 VISIT_FOR_CONTROL(expr->left(), empty_block, right_block); |
| 4952 } |
| 4953 // TODO(kmillikin): Find a way to fix this. It's ugly that there are |
| 4954 // actually two empty blocks (one here and one inserted by |
| 4955 // TestContext::BuildBranch, and that they both have an HSimulate |
| 4956 // though the second one is not a merge node, and that we really have |
| 4957 // no good AST ID to put on that first HSimulate. |
| 4958 empty_block->SetJoinId(expr->id()); |
| 4959 right_block->SetJoinId(expr->RightId()); |
| 4960 set_current_block(right_block); |
| 4961 VISIT_FOR_EFFECT(expr->right()); |
| 4962 |
| 4963 empty_block->Goto(join_block); |
| 4964 current_block()->Goto(join_block); |
| 4965 join_block->SetJoinId(expr->id()); |
| 4966 set_current_block(join_block); |
| 4967 // We did not materialize any value in the predecessor environments, |
| 4968 // so there is no need to handle it here. |
| 4937 } | 4969 } |
| 4938 | 4970 |
| 4939 } else { | 4971 } else { |
| 4940 VISIT_FOR_VALUE(expr->left()); | 4972 VISIT_FOR_VALUE(expr->left()); |
| 4941 VISIT_FOR_VALUE(expr->right()); | 4973 VISIT_FOR_VALUE(expr->right()); |
| 4942 | 4974 |
| 4943 HValue* right = Pop(); | 4975 HValue* right = Pop(); |
| 4944 HValue* left = Pop(); | 4976 HValue* left = Pop(); |
| 4945 HInstruction* instr = BuildBinaryOperation(expr, left, right); | 4977 HInstruction* instr = BuildBinaryOperation(expr, left, right); |
| 4946 instr->set_position(expr->position()); | 4978 instr->set_position(expr->position()); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5036 // change and thus prefer the general IC code. | 5068 // change and thus prefer the general IC code. |
| 5037 if (!info->isolate()->heap()->InNewSpace(*candidate)) { | 5069 if (!info->isolate()->heap()->InNewSpace(*candidate)) { |
| 5038 target = candidate; | 5070 target = candidate; |
| 5039 } | 5071 } |
| 5040 } | 5072 } |
| 5041 } | 5073 } |
| 5042 | 5074 |
| 5043 // If the target is not null we have found a known global function that is | 5075 // If the target is not null we have found a known global function that is |
| 5044 // assumed to stay the same for this instanceof. | 5076 // assumed to stay the same for this instanceof. |
| 5045 if (target.is_null()) { | 5077 if (target.is_null()) { |
| 5046 instr = new HInstanceOf(left, right); | 5078 HContext* context = new HContext; |
| 5079 AddInstruction(context); |
| 5080 instr = new HInstanceOf(context, left, right); |
| 5047 } else { | 5081 } else { |
| 5048 AddInstruction(new HCheckFunction(right, target)); | 5082 AddInstruction(new HCheckFunction(right, target)); |
| 5049 instr = new HInstanceOfKnownGlobal(left, target); | 5083 instr = new HInstanceOfKnownGlobal(left, target); |
| 5050 } | 5084 } |
| 5051 } else if (op == Token::IN) { | 5085 } else if (op == Token::IN) { |
| 5052 BAILOUT("Unsupported comparison: in"); | 5086 BAILOUT("Unsupported comparison: in"); |
| 5053 } else if (info.IsNonPrimitive()) { | 5087 } else if (info.IsNonPrimitive()) { |
| 5054 switch (op) { | 5088 switch (op) { |
| 5055 case Token::EQ: | 5089 case Token::EQ: |
| 5056 case Token::EQ_STRICT: { | 5090 case Token::EQ_STRICT: { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5101 (slot != NULL && slot->type() == Slot::LOOKUP) || | 5135 (slot != NULL && slot->type() == Slot::LOOKUP) || |
| 5102 decl->mode() == Variable::CONST || | 5136 decl->mode() == Variable::CONST || |
| 5103 decl->fun() != NULL) { | 5137 decl->fun() != NULL) { |
| 5104 BAILOUT("unsupported declaration"); | 5138 BAILOUT("unsupported declaration"); |
| 5105 } | 5139 } |
| 5106 } | 5140 } |
| 5107 | 5141 |
| 5108 | 5142 |
| 5109 // Generators for inline runtime functions. | 5143 // Generators for inline runtime functions. |
| 5110 // Support for types. | 5144 // Support for types. |
| 5111 void HGraphBuilder::GenerateIsSmi(int argument_count, int ast_id) { | 5145 void HGraphBuilder::GenerateIsSmi(CallRuntime* call) { |
| 5112 ASSERT(argument_count == 1); | 5146 ASSERT(call->arguments()->length() == 1); |
| 5147 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5113 HValue* value = Pop(); | 5148 HValue* value = Pop(); |
| 5114 HIsSmi* result = new HIsSmi(value); | 5149 HIsSmi* result = new HIsSmi(value); |
| 5115 ast_context()->ReturnInstruction(result, ast_id); | 5150 ast_context()->ReturnInstruction(result, call->id()); |
| 5116 } | 5151 } |
| 5117 | 5152 |
| 5118 | 5153 |
| 5119 void HGraphBuilder::GenerateIsSpecObject(int argument_count, int ast_id) { | 5154 void HGraphBuilder::GenerateIsSpecObject(CallRuntime* call) { |
| 5120 ASSERT(argument_count == 1); | 5155 ASSERT(call->arguments()->length() == 1); |
| 5156 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5121 HValue* value = Pop(); | 5157 HValue* value = Pop(); |
| 5122 HHasInstanceType* result = | 5158 HHasInstanceType* result = |
| 5123 new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); | 5159 new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); |
| 5124 ast_context()->ReturnInstruction(result, ast_id); | 5160 ast_context()->ReturnInstruction(result, call->id()); |
| 5125 } | 5161 } |
| 5126 | 5162 |
| 5127 | 5163 |
| 5128 void HGraphBuilder::GenerateIsFunction(int argument_count, int ast_id) { | 5164 void HGraphBuilder::GenerateIsFunction(CallRuntime* call) { |
| 5129 ASSERT(argument_count == 1); | 5165 ASSERT(call->arguments()->length() == 1); |
| 5166 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5130 HValue* value = Pop(); | 5167 HValue* value = Pop(); |
| 5131 HHasInstanceType* result = new HHasInstanceType(value, JS_FUNCTION_TYPE); | 5168 HHasInstanceType* result = new HHasInstanceType(value, JS_FUNCTION_TYPE); |
| 5132 ast_context()->ReturnInstruction(result, ast_id); | 5169 ast_context()->ReturnInstruction(result, call->id()); |
| 5133 } | 5170 } |
| 5134 | 5171 |
| 5135 | 5172 |
| 5136 void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count, | 5173 void HGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) { |
| 5137 int ast_id) { | 5174 ASSERT(call->arguments()->length() == 1); |
| 5138 ASSERT(argument_count == 1); | 5175 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5139 HValue* value = Pop(); | 5176 HValue* value = Pop(); |
| 5140 HHasCachedArrayIndex* result = new HHasCachedArrayIndex(value); | 5177 HHasCachedArrayIndex* result = new HHasCachedArrayIndex(value); |
| 5141 ast_context()->ReturnInstruction(result, ast_id); | 5178 ast_context()->ReturnInstruction(result, call->id()); |
| 5142 } | 5179 } |
| 5143 | 5180 |
| 5144 | 5181 |
| 5145 void HGraphBuilder::GenerateIsArray(int argument_count, int ast_id) { | 5182 void HGraphBuilder::GenerateIsArray(CallRuntime* call) { |
| 5146 ASSERT(argument_count == 1); | 5183 ASSERT(call->arguments()->length() == 1); |
| 5184 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5147 HValue* value = Pop(); | 5185 HValue* value = Pop(); |
| 5148 HHasInstanceType* result = new HHasInstanceType(value, JS_ARRAY_TYPE); | 5186 HHasInstanceType* result = new HHasInstanceType(value, JS_ARRAY_TYPE); |
| 5149 ast_context()->ReturnInstruction(result, ast_id); | 5187 ast_context()->ReturnInstruction(result, call->id()); |
| 5150 } | 5188 } |
| 5151 | 5189 |
| 5152 | 5190 |
| 5153 void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) { | 5191 void HGraphBuilder::GenerateIsRegExp(CallRuntime* call) { |
| 5154 ASSERT(argument_count == 1); | 5192 ASSERT(call->arguments()->length() == 1); |
| 5193 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5155 HValue* value = Pop(); | 5194 HValue* value = Pop(); |
| 5156 HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE); | 5195 HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE); |
| 5157 ast_context()->ReturnInstruction(result, ast_id); | 5196 ast_context()->ReturnInstruction(result, call->id()); |
| 5158 } | 5197 } |
| 5159 | 5198 |
| 5160 | 5199 |
| 5161 void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) { | 5200 void HGraphBuilder::GenerateIsObject(CallRuntime* call) { |
| 5162 ASSERT(argument_count == 1); | 5201 ASSERT(call->arguments()->length() == 1); |
| 5163 | 5202 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5164 HValue* value = Pop(); | 5203 HValue* value = Pop(); |
| 5165 HIsObject* test = new HIsObject(value); | 5204 HIsObject* test = new HIsObject(value); |
| 5166 ast_context()->ReturnInstruction(test, ast_id); | 5205 ast_context()->ReturnInstruction(test, call->id()); |
| 5167 } | 5206 } |
| 5168 | 5207 |
| 5169 | 5208 |
| 5170 void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count, | 5209 void HGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) { |
| 5171 int ast_id) { | |
| 5172 BAILOUT("inlined runtime function: IsNonNegativeSmi"); | 5210 BAILOUT("inlined runtime function: IsNonNegativeSmi"); |
| 5173 } | 5211 } |
| 5174 | 5212 |
| 5175 | 5213 |
| 5176 void HGraphBuilder::GenerateIsUndetectableObject(int argument_count, | 5214 void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) { |
| 5177 int ast_id) { | |
| 5178 BAILOUT("inlined runtime function: IsUndetectableObject"); | 5215 BAILOUT("inlined runtime function: IsUndetectableObject"); |
| 5179 } | 5216 } |
| 5180 | 5217 |
| 5181 | 5218 |
| 5182 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( | 5219 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( |
| 5183 int argument_count, | 5220 CallRuntime* call) { |
| 5184 int ast_id) { | |
| 5185 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); | 5221 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); |
| 5186 } | 5222 } |
| 5187 | 5223 |
| 5188 | 5224 |
| 5189 // Support for construct call checks. | 5225 // Support for construct call checks. |
| 5190 void HGraphBuilder::GenerateIsConstructCall(int argument_count, int ast_id) { | 5226 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { |
| 5191 ASSERT(argument_count == 0); | 5227 ASSERT(call->arguments()->length() == 0); |
| 5192 ast_context()->ReturnInstruction(new HIsConstructCall, ast_id); | 5228 ast_context()->ReturnInstruction(new HIsConstructCall, call->id()); |
| 5193 } | 5229 } |
| 5194 | 5230 |
| 5195 | 5231 |
| 5196 // Support for arguments.length and arguments[?]. | 5232 // Support for arguments.length and arguments[?]. |
| 5197 void HGraphBuilder::GenerateArgumentsLength(int argument_count, int ast_id) { | 5233 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { |
| 5198 ASSERT(argument_count == 0); | 5234 ASSERT(call->arguments()->length() == 0); |
| 5199 HInstruction* elements = AddInstruction(new HArgumentsElements); | 5235 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 5200 HArgumentsLength* result = new HArgumentsLength(elements); | 5236 HArgumentsLength* result = new HArgumentsLength(elements); |
| 5201 ast_context()->ReturnInstruction(result, ast_id); | 5237 ast_context()->ReturnInstruction(result, call->id()); |
| 5202 } | 5238 } |
| 5203 | 5239 |
| 5204 | 5240 |
| 5205 void HGraphBuilder::GenerateArguments(int argument_count, int ast_id) { | 5241 void HGraphBuilder::GenerateArguments(CallRuntime* call) { |
| 5206 ASSERT(argument_count == 1); | 5242 ASSERT(call->arguments()->length() == 1); |
| 5243 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5207 HValue* index = Pop(); | 5244 HValue* index = Pop(); |
| 5208 HInstruction* elements = AddInstruction(new HArgumentsElements); | 5245 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 5209 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); | 5246 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
| 5210 HAccessArgumentsAt* result = new HAccessArgumentsAt(elements, length, index); | 5247 HAccessArgumentsAt* result = new HAccessArgumentsAt(elements, length, index); |
| 5211 ast_context()->ReturnInstruction(result, ast_id); | 5248 ast_context()->ReturnInstruction(result, call->id()); |
| 5212 } | 5249 } |
| 5213 | 5250 |
| 5214 | 5251 |
| 5215 // Support for accessing the class and value fields of an object. | 5252 // Support for accessing the class and value fields of an object. |
| 5216 void HGraphBuilder::GenerateClassOf(int argument_count, int ast_id) { | 5253 void HGraphBuilder::GenerateClassOf(CallRuntime* call) { |
| 5217 // The special form detected by IsClassOfTest is detected before we get here | 5254 // The special form detected by IsClassOfTest is detected before we get here |
| 5218 // and does not cause a bailout. | 5255 // and does not cause a bailout. |
| 5219 BAILOUT("inlined runtime function: ClassOf"); | 5256 BAILOUT("inlined runtime function: ClassOf"); |
| 5220 } | 5257 } |
| 5221 | 5258 |
| 5222 | 5259 |
| 5223 void HGraphBuilder::GenerateValueOf(int argument_count, int ast_id) { | 5260 void HGraphBuilder::GenerateValueOf(CallRuntime* call) { |
| 5224 ASSERT(argument_count == 1); | 5261 ASSERT(call->arguments()->length() == 1); |
| 5262 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5225 HValue* value = Pop(); | 5263 HValue* value = Pop(); |
| 5226 HValueOf* result = new HValueOf(value); | 5264 HValueOf* result = new HValueOf(value); |
| 5227 ast_context()->ReturnInstruction(result, ast_id); | 5265 ast_context()->ReturnInstruction(result, call->id()); |
| 5228 } | 5266 } |
| 5229 | 5267 |
| 5230 | 5268 |
| 5231 void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { | 5269 void HGraphBuilder::GenerateSetValueOf(CallRuntime* call) { |
| 5232 BAILOUT("inlined runtime function: SetValueOf"); | 5270 BAILOUT("inlined runtime function: SetValueOf"); |
| 5233 } | 5271 } |
| 5234 | 5272 |
| 5235 | 5273 |
| 5236 // Fast support for charCodeAt(n). | 5274 // Fast support for charCodeAt(n). |
| 5237 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { | 5275 void HGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) { |
| 5238 ASSERT(argument_count == 2); | 5276 ASSERT(call->arguments()->length() == 2); |
| 5277 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5278 VISIT_FOR_VALUE(call->arguments()->at(1)); |
| 5239 HValue* index = Pop(); | 5279 HValue* index = Pop(); |
| 5240 HValue* string = Pop(); | 5280 HValue* string = Pop(); |
| 5241 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); | 5281 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); |
| 5242 ast_context()->ReturnInstruction(result, ast_id); | 5282 ast_context()->ReturnInstruction(result, call->id()); |
| 5243 } | 5283 } |
| 5244 | 5284 |
| 5245 | 5285 |
| 5246 // Fast support for string.charAt(n) and string[n]. | 5286 // Fast support for string.charAt(n) and string[n]. |
| 5247 void HGraphBuilder::GenerateStringCharFromCode(int argument_count, | 5287 void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) { |
| 5248 int ast_id) { | |
| 5249 BAILOUT("inlined runtime function: StringCharFromCode"); | 5288 BAILOUT("inlined runtime function: StringCharFromCode"); |
| 5250 } | 5289 } |
| 5251 | 5290 |
| 5252 | 5291 |
| 5253 // Fast support for string.charAt(n) and string[n]. | 5292 // Fast support for string.charAt(n) and string[n]. |
| 5254 void HGraphBuilder::GenerateStringCharAt(int argument_count, int ast_id) { | 5293 void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) { |
| 5255 ASSERT_EQ(2, argument_count); | 5294 ASSERT_EQ(2, call->arguments()->length()); |
| 5256 PushArgumentsForStubCall(argument_count); | 5295 VisitArgumentList(call->arguments()); |
| 5257 HCallStub* result = new HCallStub(CodeStub::StringCharAt, argument_count); | 5296 CHECK_BAILOUT; |
| 5258 ast_context()->ReturnInstruction(result, ast_id); | 5297 HContext* context = new HContext; |
| 5298 AddInstruction(context); |
| 5299 HCallStub* result = new HCallStub(context, CodeStub::StringCharAt, 2); |
| 5300 Drop(2); |
| 5301 ast_context()->ReturnInstruction(result, call->id()); |
| 5259 } | 5302 } |
| 5260 | 5303 |
| 5261 | 5304 |
| 5262 // Fast support for object equality testing. | 5305 // Fast support for object equality testing. |
| 5263 void HGraphBuilder::GenerateObjectEquals(int argument_count, int ast_id) { | 5306 void HGraphBuilder::GenerateObjectEquals(CallRuntime* call) { |
| 5264 ASSERT(argument_count == 2); | 5307 ASSERT(call->arguments()->length() == 2); |
| 5308 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5309 VISIT_FOR_VALUE(call->arguments()->at(1)); |
| 5265 HValue* right = Pop(); | 5310 HValue* right = Pop(); |
| 5266 HValue* left = Pop(); | 5311 HValue* left = Pop(); |
| 5267 HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right); | 5312 HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right); |
| 5268 ast_context()->ReturnInstruction(result, ast_id); | 5313 ast_context()->ReturnInstruction(result, call->id()); |
| 5269 } | 5314 } |
| 5270 | 5315 |
| 5271 | 5316 |
| 5272 void HGraphBuilder::GenerateLog(int argument_count, int ast_id) { | 5317 void HGraphBuilder::GenerateLog(CallRuntime* call) { |
| 5273 UNREACHABLE(); // We caught this in VisitCallRuntime. | 5318 // %_Log is ignored in optimized code. |
| 5319 ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 5274 } | 5320 } |
| 5275 | 5321 |
| 5276 | 5322 |
| 5277 // Fast support for Math.random(). | 5323 // Fast support for Math.random(). |
| 5278 void HGraphBuilder::GenerateRandomHeapNumber(int argument_count, int ast_id) { | 5324 void HGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) { |
| 5279 BAILOUT("inlined runtime function: RandomHeapNumber"); | 5325 BAILOUT("inlined runtime function: RandomHeapNumber"); |
| 5280 } | 5326 } |
| 5281 | 5327 |
| 5282 | 5328 |
| 5283 // Fast support for StringAdd. | 5329 // Fast support for StringAdd. |
| 5284 void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_id) { | 5330 void HGraphBuilder::GenerateStringAdd(CallRuntime* call) { |
| 5285 ASSERT_EQ(2, argument_count); | 5331 ASSERT_EQ(2, call->arguments()->length()); |
| 5286 PushArgumentsForStubCall(argument_count); | 5332 VisitArgumentList(call->arguments()); |
| 5287 HCallStub* result = new HCallStub(CodeStub::StringAdd, argument_count); | 5333 CHECK_BAILOUT; |
| 5288 ast_context()->ReturnInstruction(result, ast_id); | 5334 HContext* context = new HContext; |
| 5335 AddInstruction(context); |
| 5336 HCallStub* result = new HCallStub(context, CodeStub::StringAdd, 2); |
| 5337 Drop(2); |
| 5338 ast_context()->ReturnInstruction(result, call->id()); |
| 5289 } | 5339 } |
| 5290 | 5340 |
| 5291 | 5341 |
| 5292 // Fast support for SubString. | 5342 // Fast support for SubString. |
| 5293 void HGraphBuilder::GenerateSubString(int argument_count, int ast_id) { | 5343 void HGraphBuilder::GenerateSubString(CallRuntime* call) { |
| 5294 ASSERT_EQ(3, argument_count); | 5344 ASSERT_EQ(3, call->arguments()->length()); |
| 5295 PushArgumentsForStubCall(argument_count); | 5345 VisitArgumentList(call->arguments()); |
| 5296 HCallStub* result = new HCallStub(CodeStub::SubString, argument_count); | 5346 CHECK_BAILOUT; |
| 5297 ast_context()->ReturnInstruction(result, ast_id); | 5347 HContext* context = new HContext; |
| 5348 AddInstruction(context); |
| 5349 HCallStub* result = new HCallStub(context, CodeStub::SubString, 3); |
| 5350 Drop(3); |
| 5351 ast_context()->ReturnInstruction(result, call->id()); |
| 5298 } | 5352 } |
| 5299 | 5353 |
| 5300 | 5354 |
| 5301 // Fast support for StringCompare. | 5355 // Fast support for StringCompare. |
| 5302 void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_id) { | 5356 void HGraphBuilder::GenerateStringCompare(CallRuntime* call) { |
| 5303 ASSERT_EQ(2, argument_count); | 5357 ASSERT_EQ(2, call->arguments()->length()); |
| 5304 PushArgumentsForStubCall(argument_count); | 5358 VisitArgumentList(call->arguments()); |
| 5305 HCallStub* result = new HCallStub(CodeStub::StringCompare, argument_count); | 5359 CHECK_BAILOUT; |
| 5306 ast_context()->ReturnInstruction(result, ast_id); | 5360 HContext* context = new HContext; |
| 5361 AddInstruction(context); |
| 5362 HCallStub* result = new HCallStub(context, CodeStub::StringCompare, 2); |
| 5363 Drop(2); |
| 5364 ast_context()->ReturnInstruction(result, call->id()); |
| 5307 } | 5365 } |
| 5308 | 5366 |
| 5309 | 5367 |
| 5310 // Support for direct calls from JavaScript to native RegExp code. | 5368 // Support for direct calls from JavaScript to native RegExp code. |
| 5311 void HGraphBuilder::GenerateRegExpExec(int argument_count, int ast_id) { | 5369 void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) { |
| 5312 ASSERT_EQ(4, argument_count); | 5370 ASSERT_EQ(4, call->arguments()->length()); |
| 5313 PushArgumentsForStubCall(argument_count); | 5371 VisitArgumentList(call->arguments()); |
| 5314 HCallStub* result = new HCallStub(CodeStub::RegExpExec, argument_count); | 5372 CHECK_BAILOUT; |
| 5315 ast_context()->ReturnInstruction(result, ast_id); | 5373 HContext* context = new HContext; |
| 5374 AddInstruction(context); |
| 5375 HCallStub* result = new HCallStub(context, CodeStub::RegExpExec, 4); |
| 5376 Drop(4); |
| 5377 ast_context()->ReturnInstruction(result, call->id()); |
| 5316 } | 5378 } |
| 5317 | 5379 |
| 5318 | 5380 |
| 5319 // Construct a RegExp exec result with two in-object properties. | 5381 // Construct a RegExp exec result with two in-object properties. |
| 5320 void HGraphBuilder::GenerateRegExpConstructResult(int argument_count, | 5382 void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) { |
| 5321 int ast_id) { | 5383 ASSERT_EQ(3, call->arguments()->length()); |
| 5322 ASSERT_EQ(3, argument_count); | 5384 VisitArgumentList(call->arguments()); |
| 5323 PushArgumentsForStubCall(argument_count); | 5385 CHECK_BAILOUT; |
| 5386 HContext* context = new HContext; |
| 5387 AddInstruction(context); |
| 5324 HCallStub* result = | 5388 HCallStub* result = |
| 5325 new HCallStub(CodeStub::RegExpConstructResult, argument_count); | 5389 new HCallStub(context, CodeStub::RegExpConstructResult, 3); |
| 5326 ast_context()->ReturnInstruction(result, ast_id); | 5390 Drop(3); |
| 5391 ast_context()->ReturnInstruction(result, call->id()); |
| 5327 } | 5392 } |
| 5328 | 5393 |
| 5329 | 5394 |
| 5330 // Support for fast native caches. | 5395 // Support for fast native caches. |
| 5331 void HGraphBuilder::GenerateGetFromCache(int argument_count, int ast_id) { | 5396 void HGraphBuilder::GenerateGetFromCache(CallRuntime* call) { |
| 5332 BAILOUT("inlined runtime function: GetFromCache"); | 5397 BAILOUT("inlined runtime function: GetFromCache"); |
| 5333 } | 5398 } |
| 5334 | 5399 |
| 5335 | 5400 |
| 5336 // Fast support for number to string. | 5401 // Fast support for number to string. |
| 5337 void HGraphBuilder::GenerateNumberToString(int argument_count, int ast_id) { | 5402 void HGraphBuilder::GenerateNumberToString(CallRuntime* call) { |
| 5338 ASSERT_EQ(1, argument_count); | 5403 ASSERT_EQ(1, call->arguments()->length()); |
| 5339 PushArgumentsForStubCall(argument_count); | 5404 VisitArgumentList(call->arguments()); |
| 5340 HCallStub* result = new HCallStub(CodeStub::NumberToString, argument_count); | 5405 CHECK_BAILOUT; |
| 5341 ast_context()->ReturnInstruction(result, ast_id); | 5406 HContext* context = new HContext; |
| 5407 AddInstruction(context); |
| 5408 HCallStub* result = new HCallStub(context, CodeStub::NumberToString, 1); |
| 5409 Drop(1); |
| 5410 ast_context()->ReturnInstruction(result, call->id()); |
| 5342 } | 5411 } |
| 5343 | 5412 |
| 5344 | 5413 |
| 5345 // Fast swapping of elements. Takes three expressions, the object and two | 5414 // Fast swapping of elements. Takes three expressions, the object and two |
| 5346 // indices. This should only be used if the indices are known to be | 5415 // indices. This should only be used if the indices are known to be |
| 5347 // non-negative and within bounds of the elements array at the call site. | 5416 // non-negative and within bounds of the elements array at the call site. |
| 5348 void HGraphBuilder::GenerateSwapElements(int argument_count, int ast_id) { | 5417 void HGraphBuilder::GenerateSwapElements(CallRuntime* call) { |
| 5349 BAILOUT("inlined runtime function: SwapElements"); | 5418 BAILOUT("inlined runtime function: SwapElements"); |
| 5350 } | 5419 } |
| 5351 | 5420 |
| 5352 | 5421 |
| 5353 // Fast call for custom callbacks. | 5422 // Fast call for custom callbacks. |
| 5354 void HGraphBuilder::GenerateCallFunction(int argument_count, int ast_id) { | 5423 void HGraphBuilder::GenerateCallFunction(CallRuntime* call) { |
| 5355 BAILOUT("inlined runtime function: CallFunction"); | 5424 BAILOUT("inlined runtime function: CallFunction"); |
| 5356 } | 5425 } |
| 5357 | 5426 |
| 5358 | 5427 |
| 5359 // Fast call to math functions. | 5428 // Fast call to math functions. |
| 5360 void HGraphBuilder::GenerateMathPow(int argument_count, int ast_id) { | 5429 void HGraphBuilder::GenerateMathPow(CallRuntime* call) { |
| 5361 ASSERT_EQ(2, argument_count); | 5430 ASSERT_EQ(2, call->arguments()->length()); |
| 5431 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5432 VISIT_FOR_VALUE(call->arguments()->at(1)); |
| 5362 HValue* right = Pop(); | 5433 HValue* right = Pop(); |
| 5363 HValue* left = Pop(); | 5434 HValue* left = Pop(); |
| 5364 HPower* result = new HPower(left, right); | 5435 HPower* result = new HPower(left, right); |
| 5365 ast_context()->ReturnInstruction(result, ast_id); | 5436 ast_context()->ReturnInstruction(result, call->id()); |
| 5366 } | 5437 } |
| 5367 | 5438 |
| 5368 | 5439 |
| 5369 void HGraphBuilder::GenerateMathSin(int argument_count, int ast_id) { | 5440 void HGraphBuilder::GenerateMathSin(CallRuntime* call) { |
| 5370 ASSERT_EQ(1, argument_count); | 5441 ASSERT_EQ(1, call->arguments()->length()); |
| 5371 PushArgumentsForStubCall(argument_count); | 5442 VisitArgumentList(call->arguments()); |
| 5372 HCallStub* result = | 5443 CHECK_BAILOUT; |
| 5373 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5444 HContext* context = new HContext; |
| 5445 AddInstruction(context); |
| 5446 HCallStub* result = new HCallStub(context, CodeStub::TranscendentalCache, 1); |
| 5374 result->set_transcendental_type(TranscendentalCache::SIN); | 5447 result->set_transcendental_type(TranscendentalCache::SIN); |
| 5375 ast_context()->ReturnInstruction(result, ast_id); | 5448 Drop(1); |
| 5376 } | 5449 ast_context()->ReturnInstruction(result, call->id()); |
| 5377 | 5450 } |
| 5378 | 5451 |
| 5379 void HGraphBuilder::GenerateMathCos(int argument_count, int ast_id) { | 5452 |
| 5380 ASSERT_EQ(1, argument_count); | 5453 void HGraphBuilder::GenerateMathCos(CallRuntime* call) { |
| 5381 PushArgumentsForStubCall(argument_count); | 5454 ASSERT_EQ(1, call->arguments()->length()); |
| 5382 HCallStub* result = | 5455 VisitArgumentList(call->arguments()); |
| 5383 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5456 CHECK_BAILOUT; |
| 5457 HContext* context = new HContext; |
| 5458 AddInstruction(context); |
| 5459 HCallStub* result = new HCallStub(context, CodeStub::TranscendentalCache, 1); |
| 5384 result->set_transcendental_type(TranscendentalCache::COS); | 5460 result->set_transcendental_type(TranscendentalCache::COS); |
| 5385 ast_context()->ReturnInstruction(result, ast_id); | 5461 Drop(1); |
| 5386 } | 5462 ast_context()->ReturnInstruction(result, call->id()); |
| 5387 | 5463 } |
| 5388 | 5464 |
| 5389 void HGraphBuilder::GenerateMathLog(int argument_count, int ast_id) { | 5465 |
| 5390 ASSERT_EQ(1, argument_count); | 5466 void HGraphBuilder::GenerateMathLog(CallRuntime* call) { |
| 5391 PushArgumentsForStubCall(argument_count); | 5467 ASSERT_EQ(1, call->arguments()->length()); |
| 5392 HCallStub* result = | 5468 VisitArgumentList(call->arguments()); |
| 5393 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5469 CHECK_BAILOUT; |
| 5470 HContext* context = new HContext; |
| 5471 AddInstruction(context); |
| 5472 HCallStub* result = new HCallStub(context, CodeStub::TranscendentalCache, 1); |
| 5394 result->set_transcendental_type(TranscendentalCache::LOG); | 5473 result->set_transcendental_type(TranscendentalCache::LOG); |
| 5395 ast_context()->ReturnInstruction(result, ast_id); | 5474 Drop(1); |
| 5396 } | 5475 ast_context()->ReturnInstruction(result, call->id()); |
| 5397 | 5476 } |
| 5398 | 5477 |
| 5399 void HGraphBuilder::GenerateMathSqrt(int argument_count, int ast_id) { | 5478 |
| 5479 void HGraphBuilder::GenerateMathSqrt(CallRuntime* call) { |
| 5400 BAILOUT("inlined runtime function: MathSqrt"); | 5480 BAILOUT("inlined runtime function: MathSqrt"); |
| 5401 } | 5481 } |
| 5402 | 5482 |
| 5403 | 5483 |
| 5404 // Check whether two RegExps are equivalent | 5484 // Check whether two RegExps are equivalent |
| 5405 void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count, | 5485 void HGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) { |
| 5406 int ast_id) { | |
| 5407 BAILOUT("inlined runtime function: IsRegExpEquivalent"); | 5486 BAILOUT("inlined runtime function: IsRegExpEquivalent"); |
| 5408 } | 5487 } |
| 5409 | 5488 |
| 5410 | 5489 |
| 5411 void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count, | 5490 void HGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) { |
| 5412 int ast_id) { | 5491 ASSERT(call->arguments()->length() == 1); |
| 5413 BAILOUT("inlined runtime function: GetCachedArrayIndex"); | 5492 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5414 } | 5493 HValue* value = Pop(); |
| 5415 | 5494 HGetCachedArrayIndex* result = new HGetCachedArrayIndex(value); |
| 5416 | 5495 ast_context()->ReturnInstruction(result, call->id()); |
| 5417 void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count, | 5496 } |
| 5418 int ast_id) { | 5497 |
| 5498 |
| 5499 void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { |
| 5419 BAILOUT("inlined runtime function: FastAsciiArrayJoin"); | 5500 BAILOUT("inlined runtime function: FastAsciiArrayJoin"); |
| 5420 } | 5501 } |
| 5421 | 5502 |
| 5422 | 5503 |
| 5423 #undef BAILOUT | 5504 #undef BAILOUT |
| 5424 #undef CHECK_BAILOUT | 5505 #undef CHECK_BAILOUT |
| 5425 #undef VISIT_FOR_EFFECT | 5506 #undef VISIT_FOR_EFFECT |
| 5426 #undef VISIT_FOR_VALUE | 5507 #undef VISIT_FOR_VALUE |
| 5427 #undef ADD_TO_SUBGRAPH | 5508 #undef ADD_TO_SUBGRAPH |
| 5428 | 5509 |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5809 if (range->IsChild()) { | 5890 if (range->IsChild()) { |
| 5810 parent_index = range->parent()->id(); | 5891 parent_index = range->parent()->id(); |
| 5811 } else { | 5892 } else { |
| 5812 parent_index = range->id(); | 5893 parent_index = range->id(); |
| 5813 } | 5894 } |
| 5814 LOperand* op = range->FirstHint(); | 5895 LOperand* op = range->FirstHint(); |
| 5815 int hint_index = -1; | 5896 int hint_index = -1; |
| 5816 if (op != NULL && op->IsUnallocated()) hint_index = op->VirtualRegister(); | 5897 if (op != NULL && op->IsUnallocated()) hint_index = op->VirtualRegister(); |
| 5817 trace_.Add(" %d %d", parent_index, hint_index); | 5898 trace_.Add(" %d %d", parent_index, hint_index); |
| 5818 UseInterval* cur_interval = range->first_interval(); | 5899 UseInterval* cur_interval = range->first_interval(); |
| 5819 while (cur_interval != NULL) { | 5900 while (cur_interval != NULL && range->Covers(cur_interval->start())) { |
| 5820 trace_.Add(" [%d, %d[", | 5901 trace_.Add(" [%d, %d[", |
| 5821 cur_interval->start().Value(), | 5902 cur_interval->start().Value(), |
| 5822 cur_interval->end().Value()); | 5903 cur_interval->end().Value()); |
| 5823 cur_interval = cur_interval->next(); | 5904 cur_interval = cur_interval->next(); |
| 5824 } | 5905 } |
| 5825 | 5906 |
| 5826 UsePosition* current_pos = range->first_pos(); | 5907 UsePosition* current_pos = range->first_pos(); |
| 5827 while (current_pos != NULL) { | 5908 while (current_pos != NULL) { |
| 5828 if (current_pos->RegisterIsBeneficial()) { | 5909 if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) { |
| 5829 trace_.Add(" %d M", current_pos->pos().Value()); | 5910 trace_.Add(" %d M", current_pos->pos().Value()); |
| 5830 } | 5911 } |
| 5831 current_pos = current_pos->next(); | 5912 current_pos = current_pos->next(); |
| 5832 } | 5913 } |
| 5833 | 5914 |
| 5834 trace_.Add(" \"\"\n"); | 5915 trace_.Add(" \"\"\n"); |
| 5835 } | 5916 } |
| 5836 } | 5917 } |
| 5837 | 5918 |
| 5838 | 5919 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5926 } | 6007 } |
| 5927 } | 6008 } |
| 5928 | 6009 |
| 5929 #ifdef DEBUG | 6010 #ifdef DEBUG |
| 5930 if (graph_ != NULL) graph_->Verify(); | 6011 if (graph_ != NULL) graph_->Verify(); |
| 5931 if (allocator_ != NULL) allocator_->Verify(); | 6012 if (allocator_ != NULL) allocator_->Verify(); |
| 5932 #endif | 6013 #endif |
| 5933 } | 6014 } |
| 5934 | 6015 |
| 5935 } } // namespace v8::internal | 6016 } } // namespace v8::internal |
| OLD | NEW |