Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(303)

Side by Side Diff: src/hydrogen.cc

Issue 5812005: Deoptimize non-smi switch cases if they are reached. (Closed)
Patch Set: Rebased Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/ia32/full-codegen-ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « no previous file | src/ia32/full-codegen-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698