OLD | NEW |
---|---|
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 2556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2567 clause_value, | 2567 clause_value, |
2568 Token::EQ_STRICT); | 2568 Token::EQ_STRICT); |
2569 compare->SetInputRepresentation(Representation::Integer32()); | 2569 compare->SetInputRepresentation(Representation::Integer32()); |
2570 subgraph->exit_block()->AddInstruction(compare); | 2570 subgraph->exit_block()->AddInstruction(compare); |
2571 return compare; | 2571 return compare; |
2572 } | 2572 } |
2573 | 2573 |
2574 | 2574 |
2575 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 2575 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
2576 VISIT_FOR_VALUE(stmt->tag()); | 2576 VISIT_FOR_VALUE(stmt->tag()); |
2577 // TODO(3168478): simulate added for tag should be enough. | |
2578 AddSimulate(stmt->EntryId()); | |
2577 HValue* switch_value = Pop(); | 2579 HValue* switch_value = Pop(); |
2578 | 2580 |
2579 ZoneList<CaseClause*>* clauses = stmt->cases(); | 2581 ZoneList<CaseClause*>* clauses = stmt->cases(); |
2580 int num_clauses = clauses->length(); | 2582 int num_clauses = clauses->length(); |
2581 if (num_clauses == 0) return; | 2583 if (num_clauses == 0) return; |
2582 if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses"); | 2584 if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses"); |
2583 | 2585 |
2586 int num_smi_clauses = num_clauses; | |
2584 for (int i = 0; i < num_clauses; i++) { | 2587 for (int i = 0; i < num_clauses; i++) { |
2585 CaseClause* clause = clauses->at(i); | 2588 CaseClause* clause = clauses->at(i); |
2586 if (clause->is_default()) continue; | 2589 if (clause->is_default()) continue; |
2587 clause->RecordTypeFeedback(oracle()); | 2590 clause->RecordTypeFeedback(oracle()); |
2588 if (!clause->IsSmiCompare()) BAILOUT("SwitchStatement: non-smi compare"); | 2591 if (!clause->IsSmiCompare()) { |
2592 // We will deoptimize if the first non-smi compare is reached. | |
2593 num_smi_clauses = i; | |
2594 break; | |
2595 } | |
fschneider
2010/12/15 16:12:13
Does it make sense to check if all clauses have a
| |
2589 if (!clause->label()->IsSmiLiteral()) { | 2596 if (!clause->label()->IsSmiLiteral()) { |
2590 BAILOUT("SwitchStatement: non-literal switch label"); | 2597 BAILOUT("SwitchStatement: non-literal switch label"); |
2591 } | 2598 } |
2592 } | 2599 } |
2593 | 2600 |
2594 // The single exit block of the whole switch statement. | 2601 // The single exit block of the whole switch statement. |
2595 HBasicBlock* single_exit_block = graph_->CreateBasicBlock(); | 2602 HBasicBlock* single_exit_block = graph_->CreateBasicBlock(); |
2596 | 2603 |
2597 // Build a series of empty subgraphs for the comparisons. | 2604 // Build a series of empty subgraphs for the comparisons. |
2598 // The default clause does not have a comparison subgraph. | 2605 // The default clause does not have a comparison subgraph. |
2599 ZoneList<HSubgraph*> compare_graphs(num_clauses); | 2606 ZoneList<HSubgraph*> compare_graphs(num_smi_clauses); |
2600 for (int i = 0; i < num_clauses; i++) { | 2607 for (int i = 0; i < num_smi_clauses; i++) { |
2601 HSubgraph* subgraph = !clauses->at(i)->is_default() | 2608 if (clauses->at(i)->is_default()) { |
2602 ? CreateEmptySubgraph() | 2609 compare_graphs.Add(NULL); |
2603 : NULL; | 2610 } else { |
2604 compare_graphs.Add(subgraph); | 2611 compare_graphs.Add(CreateEmptySubgraph()); |
2612 } | |
2605 } | 2613 } |
2606 | 2614 |
2607 HSubgraph* prev_graph = current_subgraph_; | 2615 HSubgraph* prev_graph = current_subgraph_; |
2608 HCompare* prev_compare_inst = NULL; | 2616 HCompare* prev_compare_inst = NULL; |
2609 for (int i = 0; i < num_clauses; i++) { | 2617 for (int i = 0; i < num_smi_clauses; i++) { |
2610 CaseClause* clause = clauses->at(i); | 2618 CaseClause* clause = clauses->at(i); |
2611 if (clause->is_default()) continue; | 2619 if (clause->is_default()) continue; |
2612 | 2620 |
2613 // Finish the previous graph by connecting it to the current. | 2621 // Finish the previous graph by connecting it to the current. |
2614 HSubgraph* subgraph = compare_graphs.at(i); | 2622 HSubgraph* subgraph = compare_graphs.at(i); |
2615 if (prev_compare_inst == NULL) { | 2623 if (prev_compare_inst == NULL) { |
2616 ASSERT(prev_graph == current_subgraph_); | 2624 ASSERT(prev_graph == current_subgraph_); |
2617 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); | 2625 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); |
2618 } else { | 2626 } else { |
2619 HBasicBlock* empty = graph()->CreateBasicBlock(); | 2627 HBasicBlock* empty = graph()->CreateBasicBlock(); |
2620 prev_graph->exit_block()->Finish(new HBranch(empty, | 2628 prev_graph->exit_block()->Finish(new HBranch(empty, |
2621 subgraph->entry_block(), | 2629 subgraph->entry_block(), |
2622 prev_compare_inst)); | 2630 prev_compare_inst)); |
2623 } | 2631 } |
2624 | 2632 |
2625 // Build instructions for current subgraph. | 2633 // Build instructions for current subgraph. |
2634 ASSERT(clause->IsSmiCompare()); | |
2626 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); | 2635 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); |
2627 if (HasStackOverflow()) return; | 2636 if (HasStackOverflow()) return; |
2628 | 2637 |
2629 prev_graph = subgraph; | 2638 prev_graph = subgraph; |
2630 } | 2639 } |
2631 | 2640 |
2632 // Finish last comparison if there was at least one comparison. | 2641 // Finish last comparison if there was at least one comparison. |
2633 // last_false_block is the (empty) false-block of the last comparison. If | 2642 // last_false_block is the (empty) false-block of the last comparison. If |
2634 // there are no comparisons at all (a single default clause), it is just | 2643 // there are no comparisons at all (a single default clause), it is just |
2635 // the last block of the current subgraph. | 2644 // the last block of the current subgraph. |
2636 HBasicBlock* last_false_block = current_subgraph_->exit_block(); | 2645 HBasicBlock* last_false_block = current_subgraph_->exit_block(); |
2637 if (prev_graph != current_subgraph_) { | 2646 if (prev_graph != current_subgraph_) { |
2638 last_false_block = graph()->CreateBasicBlock(); | 2647 last_false_block = graph()->CreateBasicBlock(); |
2639 HBasicBlock* empty = graph()->CreateBasicBlock(); | 2648 HBasicBlock* empty = graph()->CreateBasicBlock(); |
2640 prev_graph->exit_block()->Finish(new HBranch(empty, | 2649 prev_graph->exit_block()->Finish(new HBranch(empty, |
2641 last_false_block, | 2650 last_false_block, |
2642 prev_compare_inst)); | 2651 prev_compare_inst)); |
2643 } | 2652 } |
2644 | 2653 |
2654 // If we have a non-smi compare clause, we deoptimize after trying | |
2655 // all the previous compares. | |
2656 if (num_smi_clauses < num_clauses) { | |
2657 last_false_block->Finish(new HDeoptimize); | |
2658 } | |
2659 | |
2645 // Build statement blocks, connect them to their comparison block and | 2660 // Build statement blocks, connect them to their comparison block and |
2646 // to the previous statement block, if there is a fall-through. | 2661 // to the previous statement block, if there is a fall-through. |
2647 HSubgraph* previous_subgraph = NULL; | 2662 HSubgraph* previous_subgraph = NULL; |
2648 for (int i = 0; i < num_clauses; i++) { | 2663 for (int i = 0; i < num_clauses; i++) { |
2649 CaseClause* clause = clauses->at(i); | 2664 CaseClause* clause = clauses->at(i); |
2650 HSubgraph* subgraph = CreateEmptySubgraph(); | 2665 // Subgraph for the statements of the clause is only created when |
2666 // it's reachable either from the corresponding compare or as a | |
2667 // fall-through from previous statements. | |
2668 HSubgraph* subgraph = NULL; | |
2651 | 2669 |
2652 if (clause->is_default()) { | 2670 if (i < num_smi_clauses) { |
2653 // Default clause: Connect it to the last false block. | 2671 if (clause->is_default()) { |
2654 last_false_block->Finish(new HGoto(subgraph->entry_block())); | 2672 if (!last_false_block->IsFinished()) { |
2655 } else { | 2673 // Default clause: Connect it to the last false block. |
2656 // Connect with the corresponding comparison. | 2674 subgraph = CreateEmptySubgraph(); |
2657 HBasicBlock* empty = | 2675 last_false_block->Finish(new HGoto(subgraph->entry_block())); |
2658 compare_graphs.at(i)->exit_block()->end()->FirstSuccessor(); | 2676 } |
2659 empty->Finish(new HGoto(subgraph->entry_block())); | 2677 } else { |
2678 ASSERT(clause->IsSmiCompare()); | |
2679 // Connect with the corresponding comparison. | |
2680 subgraph = CreateEmptySubgraph(); | |
2681 HBasicBlock* empty = | |
2682 compare_graphs.at(i)->exit_block()->end()->FirstSuccessor(); | |
2683 empty->Finish(new HGoto(subgraph->entry_block())); | |
2684 } | |
2660 } | 2685 } |
2661 | 2686 |
2662 // Check for fall-through from previous statement block. | 2687 // Check for fall-through from previous statement block. |
2663 if (previous_subgraph != NULL && previous_subgraph->HasExit()) { | 2688 if (previous_subgraph != NULL && previous_subgraph->HasExit()) { |
2689 if (subgraph == NULL) subgraph = CreateEmptySubgraph(); | |
2664 previous_subgraph->exit_block()-> | 2690 previous_subgraph->exit_block()-> |
2665 Finish(new HGoto(subgraph->entry_block())); | 2691 Finish(new HGoto(subgraph->entry_block())); |
2666 } | 2692 } |
2667 | 2693 |
2668 ADD_TO_SUBGRAPH(subgraph, clause->statements()); | 2694 if (subgraph != NULL) { |
2669 HBasicBlock* break_block = subgraph->BundleBreak(stmt); | 2695 ADD_TO_SUBGRAPH(subgraph, clause->statements()); |
2670 if (break_block != NULL) { | 2696 HBasicBlock* break_block = subgraph->BundleBreak(stmt); |
2671 break_block->Finish(new HGoto(single_exit_block)); | 2697 if (break_block != NULL) { |
2698 break_block->Finish(new HGoto(single_exit_block)); | |
2699 } | |
2672 } | 2700 } |
2673 | 2701 |
2674 previous_subgraph = subgraph; | 2702 previous_subgraph = subgraph; |
2675 } | 2703 } |
2676 | 2704 |
2677 // If the last statement block has a fall-through, connect it to the | 2705 // If the last statement block has a fall-through, connect it to the |
2678 // single exit block. | 2706 // single exit block. |
2679 if (previous_subgraph->HasExit()) { | 2707 if (previous_subgraph != NULL && previous_subgraph->HasExit()) { |
2680 previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block)); | 2708 previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block)); |
2681 } | 2709 } |
2682 | 2710 |
2683 // If there is no default clause finish the last comparison's false target. | 2711 // If there is no default clause finish the last comparison's false target. |
2684 if (!last_false_block->IsFinished()) { | 2712 if (!last_false_block->IsFinished()) { |
2685 last_false_block->Finish(new HGoto(single_exit_block)); | 2713 last_false_block->Finish(new HGoto(single_exit_block)); |
2686 } | 2714 } |
2687 | 2715 |
2688 if (single_exit_block->HasPredecessor()) { | 2716 if (single_exit_block->HasPredecessor()) { |
2689 current_subgraph_->set_exit_block(single_exit_block); | 2717 current_subgraph_->set_exit_block(single_exit_block); |
(...skipping 2981 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5671 } | 5699 } |
5672 | 5700 |
5673 #ifdef DEBUG | 5701 #ifdef DEBUG |
5674 if (graph_ != NULL) graph_->Verify(); | 5702 if (graph_ != NULL) graph_->Verify(); |
5675 if (chunk_ != NULL) chunk_->Verify(); | 5703 if (chunk_ != NULL) chunk_->Verify(); |
5676 if (allocator_ != NULL) allocator_->Verify(); | 5704 if (allocator_ != NULL) allocator_->Verify(); |
5677 #endif | 5705 #endif |
5678 } | 5706 } |
5679 | 5707 |
5680 } } // namespace v8::internal | 5708 } } // namespace v8::internal |
OLD | NEW |