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 2342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2353 } | 2353 } |
2354 | 2354 |
2355 | 2355 |
2356 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { | 2356 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { |
2357 HBasicBlock* b = graph()->CreateBasicBlock(); | 2357 HBasicBlock* b = graph()->CreateBasicBlock(); |
2358 b->SetInitialEnvironment(env); | 2358 b->SetInitialEnvironment(env); |
2359 return b; | 2359 return b; |
2360 } | 2360 } |
2361 | 2361 |
2362 | 2362 |
2363 HSubgraph* HGraphBuilder::CreateEmptySubgraph() { | |
2364 HSubgraph* subgraph = new HSubgraph(graph()); | |
2365 subgraph->Initialize(graph()->CreateBasicBlock()); | |
2366 return subgraph; | |
2367 } | |
2368 | |
2369 | |
2370 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { | 2363 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { |
2371 HBasicBlock* header = graph()->CreateBasicBlock(); | 2364 HBasicBlock* header = graph()->CreateBasicBlock(); |
2372 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); | 2365 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); |
2373 header->SetInitialEnvironment(entry_env); | 2366 header->SetInitialEnvironment(entry_env); |
2374 header->AttachLoopInformation(); | 2367 header->AttachLoopInformation(); |
2375 return header; | 2368 return header; |
2376 } | 2369 } |
2377 | 2370 |
2378 | 2371 |
2379 void HGraphBuilder::VisitBlock(Block* stmt) { | 2372 void HGraphBuilder::VisitBlock(Block* stmt) { |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2507 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { | 2500 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { |
2508 BAILOUT("WithEnterStatement"); | 2501 BAILOUT("WithEnterStatement"); |
2509 } | 2502 } |
2510 | 2503 |
2511 | 2504 |
2512 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) { | 2505 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) { |
2513 BAILOUT("WithExitStatement"); | 2506 BAILOUT("WithExitStatement"); |
2514 } | 2507 } |
2515 | 2508 |
2516 | 2509 |
2517 HCompare* HGraphBuilder::BuildSwitchCompare(HSubgraph* subgraph, | |
2518 HValue* switch_value, | |
2519 CaseClause* clause) { | |
2520 AddToSubgraph(subgraph, clause->label()); | |
2521 if (HasStackOverflow()) return NULL; | |
2522 HValue* clause_value = subgraph->exit_block()->last_environment()->Pop(); | |
2523 HCompare* compare = new HCompare(switch_value, | |
2524 clause_value, | |
2525 Token::EQ_STRICT); | |
2526 compare->SetInputRepresentation(Representation::Integer32()); | |
2527 subgraph->exit_block()->AddInstruction(compare); | |
2528 return compare; | |
2529 } | |
2530 | |
2531 | |
2532 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 2510 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| 2511 // We only optimize switch statements with smi-literal smi comparisons, |
| 2512 // with a bounded number of clauses. |
| 2513 const int kCaseClauseLimit = 128; |
| 2514 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 2515 int clause_count = clauses->length(); |
| 2516 if (clause_count > kCaseClauseLimit) { |
| 2517 BAILOUT("SwitchStatement: too many clauses"); |
| 2518 } |
| 2519 |
2533 VISIT_FOR_VALUE(stmt->tag()); | 2520 VISIT_FOR_VALUE(stmt->tag()); |
2534 // TODO(3168478): simulate added for tag should be enough. | 2521 HValue* tag_value = Pop(); |
2535 AddSimulate(stmt->EntryId()); | 2522 HBasicBlock* first_test_block = current_block(); |
2536 HValue* switch_value = Pop(); | |
2537 | 2523 |
2538 ZoneList<CaseClause*>* clauses = stmt->cases(); | 2524 // 1. Build all the tests, with dangling true branches. Unconditionally |
2539 int num_clauses = clauses->length(); | 2525 // deoptimize if we encounter a non-smi comparison. |
2540 if (num_clauses == 0) return; | 2526 for (int i = 0; i < clause_count; ++i) { |
2541 if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses"); | |
2542 | |
2543 int num_smi_clauses = num_clauses; | |
2544 for (int i = 0; i < num_clauses; i++) { | |
2545 CaseClause* clause = clauses->at(i); | 2527 CaseClause* clause = clauses->at(i); |
2546 if (clause->is_default()) continue; | 2528 if (clause->is_default()) continue; |
2547 clause->RecordTypeFeedback(oracle()); | |
2548 if (!clause->IsSmiCompare()) { | |
2549 if (i == 0) BAILOUT("SwitchStatement: no smi compares"); | |
2550 // We will deoptimize if the first non-smi compare is reached. | |
2551 num_smi_clauses = i; | |
2552 break; | |
2553 } | |
2554 if (!clause->label()->IsSmiLiteral()) { | 2529 if (!clause->label()->IsSmiLiteral()) { |
2555 BAILOUT("SwitchStatement: non-literal switch label"); | 2530 BAILOUT("SwitchStatement: non-literal switch label"); |
2556 } | 2531 } |
| 2532 |
| 2533 // Unconditionally deoptimize on the first non-smi compare. |
| 2534 clause->RecordTypeFeedback(oracle()); |
| 2535 if (!clause->IsSmiCompare()) { |
| 2536 if (current_block() == first_test_block) { |
| 2537 // If the first test is the one that deopts and if the tag value is |
| 2538 // a phi, we need to have some use of that phi to prevent phi |
| 2539 // elimination from removing it. This HSimulate is such a use. |
| 2540 Push(tag_value); |
| 2541 AddSimulate(stmt->EntryId()); |
| 2542 Drop(1); |
| 2543 } |
| 2544 current_block()->Finish(new HDeoptimize()); |
| 2545 set_current_block(NULL); |
| 2546 break; |
| 2547 } |
| 2548 |
| 2549 // Otherwise generate a compare and branch. |
| 2550 VISIT_FOR_VALUE(clause->label()); |
| 2551 HValue* label_value = Pop(); |
| 2552 HCompare* compare = new HCompare(tag_value, label_value, Token::EQ_STRICT); |
| 2553 compare->SetInputRepresentation(Representation::Integer32()); |
| 2554 ASSERT(!compare->HasSideEffects()); |
| 2555 AddInstruction(compare); |
| 2556 HBasicBlock* body_block = graph()->CreateBasicBlock(); |
| 2557 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); |
| 2558 HTest* branch = new HTest(compare, body_block, next_test_block); |
| 2559 current_block()->Finish(branch); |
| 2560 set_current_block(next_test_block); |
2557 } | 2561 } |
2558 | 2562 |
2559 // The single exit block of the whole switch statement. | 2563 // Save the current block for to use for the default or to join with the |
2560 HBasicBlock* single_exit_block = graph_->CreateBasicBlock(); | 2564 // exit. This block can be NULL if we deoptimized. |
| 2565 HBasicBlock* last_block = current_block(); |
2561 | 2566 |
2562 // Build a series of empty subgraphs for the comparisons. | 2567 // 2. Loop over the clauses and the linked list of tests in lockstep, |
2563 // The default clause does not have a comparison subgraph. | 2568 // translating the clause bodies. |
2564 ZoneList<HSubgraph*> compare_graphs(num_smi_clauses); | 2569 HBasicBlock* curr_test_block = first_test_block; |
2565 for (int i = 0; i < num_smi_clauses; i++) { | 2570 HBasicBlock* fall_through_block = NULL; |
2566 if (clauses->at(i)->is_default()) { | 2571 BreakAndContinueInfo break_info(stmt); |
2567 compare_graphs.Add(NULL); | 2572 { BreakAndContinueScope push(&break_info, this); |
2568 } else { | 2573 for (int i = 0; i < clause_count; ++i) { |
2569 compare_graphs.Add(CreateEmptySubgraph()); | 2574 CaseClause* clause = clauses->at(i); |
| 2575 |
| 2576 // Identify the block where normal (non-fall-through) control flow |
| 2577 // comes from. |
| 2578 HBasicBlock* normal_block = NULL; |
| 2579 if (clause->is_default()) { |
| 2580 normal_block = last_block; |
| 2581 last_block = NULL; // Cleared to indicate we've handled it. |
| 2582 } else if (!curr_test_block->end()->IsDeoptimize()) { |
| 2583 normal_block = curr_test_block->end()->FirstSuccessor(); |
| 2584 curr_test_block = curr_test_block->end()->SecondSuccessor(); |
| 2585 } |
| 2586 |
| 2587 // Identify a block to emit the body into. |
| 2588 if (normal_block == NULL) { |
| 2589 if (fall_through_block == NULL) { |
| 2590 // (a) Unreachable. |
| 2591 continue; |
| 2592 } else { |
| 2593 // (b) Reachable only as fall through. |
| 2594 set_current_block(fall_through_block); |
| 2595 } |
| 2596 } else if (fall_through_block == NULL) { |
| 2597 // (c) Reachable only normally. |
| 2598 set_current_block(normal_block); |
| 2599 } else { |
| 2600 // (d) Reachable both ways. |
| 2601 HBasicBlock* join = CreateJoin(fall_through_block, |
| 2602 normal_block, |
| 2603 clause->EntryId()); |
| 2604 set_current_block(join); |
| 2605 } |
| 2606 |
| 2607 VisitStatements(clause->statements()); |
| 2608 CHECK_BAILOUT; |
| 2609 fall_through_block = current_block(); |
2570 } | 2610 } |
2571 } | 2611 } |
2572 | 2612 |
2573 HSubgraph* prev_graph = current_subgraph_; | 2613 // Create an up-to-3-way join. Use the break block if it exists since |
2574 HCompare* prev_compare_inst = NULL; | 2614 // it's already a join block. |
2575 for (int i = 0; i < num_smi_clauses; i++) { | 2615 HBasicBlock* break_block = break_info.break_block(); |
2576 CaseClause* clause = clauses->at(i); | 2616 if (break_block == NULL) { |
2577 if (clause->is_default()) continue; | 2617 set_current_block(CreateJoin(fall_through_block, |
2578 | 2618 last_block, |
2579 // Finish the previous graph by connecting it to the current. | 2619 stmt->ExitId())); |
2580 HSubgraph* subgraph = compare_graphs.at(i); | |
2581 if (prev_compare_inst == NULL) { | |
2582 ASSERT(prev_graph == current_subgraph_); | |
2583 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); | |
2584 } else { | |
2585 HBasicBlock* empty = graph()->CreateBasicBlock(); | |
2586 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst, | |
2587 empty, | |
2588 subgraph->entry_block())); | |
2589 } | |
2590 | |
2591 // Build instructions for current subgraph. | |
2592 ASSERT(clause->IsSmiCompare()); | |
2593 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); | |
2594 if (HasStackOverflow()) return; | |
2595 | |
2596 prev_graph = subgraph; | |
2597 } | |
2598 | |
2599 // Finish last comparison if there was at least one comparison. | |
2600 // last_false_block is the (empty) false-block of the last comparison. If | |
2601 // there are no comparisons at all (a single default clause), it is just | |
2602 // the last block of the current subgraph. | |
2603 HBasicBlock* last_false_block = current_block(); | |
2604 if (prev_graph != current_subgraph_) { | |
2605 last_false_block = graph()->CreateBasicBlock(); | |
2606 HBasicBlock* empty = graph()->CreateBasicBlock(); | |
2607 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst, | |
2608 empty, | |
2609 last_false_block)); | |
2610 } | |
2611 | |
2612 // If we have a non-smi compare clause, we deoptimize after trying | |
2613 // all the previous compares. | |
2614 if (num_smi_clauses < num_clauses) { | |
2615 last_false_block->Finish(new HDeoptimize); | |
2616 } | |
2617 | |
2618 // Build statement blocks, connect them to their comparison block and | |
2619 // to the previous statement block, if there is a fall-through. | |
2620 HSubgraph* previous_subgraph = NULL; | |
2621 for (int i = 0; i < num_clauses; i++) { | |
2622 CaseClause* clause = clauses->at(i); | |
2623 // Subgraph for the statements of the clause is only created when | |
2624 // it's reachable either from the corresponding compare or as a | |
2625 // fall-through from previous statements. | |
2626 HSubgraph* subgraph = NULL; | |
2627 | |
2628 if (i < num_smi_clauses) { | |
2629 if (clause->is_default()) { | |
2630 if (!last_false_block->IsFinished()) { | |
2631 // Default clause: Connect it to the last false block. | |
2632 subgraph = CreateEmptySubgraph(); | |
2633 last_false_block->Finish(new HGoto(subgraph->entry_block())); | |
2634 } | |
2635 } else { | |
2636 ASSERT(clause->IsSmiCompare()); | |
2637 // Connect with the corresponding comparison. | |
2638 subgraph = CreateEmptySubgraph(); | |
2639 HBasicBlock* empty = | |
2640 compare_graphs.at(i)->exit_block()->end()->FirstSuccessor(); | |
2641 empty->Finish(new HGoto(subgraph->entry_block())); | |
2642 } | |
2643 } | |
2644 | |
2645 // Check for fall-through from previous statement block. | |
2646 if (previous_subgraph != NULL && previous_subgraph->exit_block() != NULL) { | |
2647 if (subgraph == NULL) subgraph = CreateEmptySubgraph(); | |
2648 previous_subgraph->exit_block()-> | |
2649 Finish(new HGoto(subgraph->entry_block())); | |
2650 } | |
2651 | |
2652 if (subgraph != NULL) { | |
2653 BreakAndContinueInfo break_info(stmt); | |
2654 { BreakAndContinueScope push(&break_info, this); | |
2655 ADD_TO_SUBGRAPH(subgraph, clause->statements()); | |
2656 } | |
2657 if (break_info.break_block() != NULL) { | |
2658 break_info.break_block()->SetJoinId(stmt->ExitId()); | |
2659 break_info.break_block()->Finish(new HGoto(single_exit_block)); | |
2660 } | |
2661 } | |
2662 | |
2663 previous_subgraph = subgraph; | |
2664 } | |
2665 | |
2666 // If the last statement block has a fall-through, connect it to the | |
2667 // single exit block. | |
2668 if (previous_subgraph != NULL && previous_subgraph->exit_block() != NULL) { | |
2669 previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block)); | |
2670 } | |
2671 | |
2672 // If there is no default clause finish the last comparison's false target. | |
2673 if (!last_false_block->IsFinished()) { | |
2674 last_false_block->Finish(new HGoto(single_exit_block)); | |
2675 } | |
2676 | |
2677 if (single_exit_block->HasPredecessor()) { | |
2678 set_current_block(single_exit_block); | |
2679 } else { | 2620 } else { |
2680 set_current_block(NULL); | 2621 if (fall_through_block != NULL) fall_through_block->Goto(break_block); |
| 2622 if (last_block != NULL) last_block->Goto(break_block); |
| 2623 break_block->SetJoinId(stmt->ExitId()); |
| 2624 set_current_block(break_block); |
2681 } | 2625 } |
2682 } | 2626 } |
2683 | 2627 |
| 2628 |
2684 bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) { | 2629 bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) { |
2685 return statement->OsrEntryId() == info()->osr_ast_id(); | 2630 return statement->OsrEntryId() == info()->osr_ast_id(); |
2686 } | 2631 } |
2687 | 2632 |
2688 | 2633 |
2689 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { | 2634 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { |
2690 if (!HasOsrEntryAt(statement)) return; | 2635 if (!HasOsrEntryAt(statement)) return; |
2691 | 2636 |
2692 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); | 2637 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); |
2693 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); | 2638 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); |
(...skipping 3297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5991 } | 5936 } |
5992 } | 5937 } |
5993 | 5938 |
5994 #ifdef DEBUG | 5939 #ifdef DEBUG |
5995 if (graph_ != NULL) graph_->Verify(); | 5940 if (graph_ != NULL) graph_->Verify(); |
5996 if (allocator_ != NULL) allocator_->Verify(); | 5941 if (allocator_ != NULL) allocator_->Verify(); |
5997 #endif | 5942 #endif |
5998 } | 5943 } |
5999 | 5944 |
6000 } } // namespace v8::internal | 5945 } } // namespace v8::internal |
OLD | NEW |