Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_builder.h" | 5 #include "vm/flow_graph_builder.h" |
| 6 | 6 |
| 7 #include "vm/ast_printer.h" | 7 #include "vm/ast_printer.h" |
| 8 #include "vm/flags.h" | 8 #include "vm/flags.h" |
| 9 #include "vm/intermediate_language.h" | 9 #include "vm/intermediate_language.h" |
| 10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
| (...skipping 683 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 694 | 694 |
| 695 node->true_branch()->Visit(&for_true); | 695 node->true_branch()->Visit(&for_true); |
| 696 // The for_false graph fragment will be empty (default graph fragment) if | 696 // The for_false graph fragment will be empty (default graph fragment) if |
| 697 // we do not call Visit. | 697 // we do not call Visit. |
| 698 if (node->false_branch() != NULL) node->false_branch()->Visit(&for_false); | 698 if (node->false_branch() != NULL) node->false_branch()->Visit(&for_false); |
| 699 Join(for_test, for_true, for_false); | 699 Join(for_test, for_true, for_false); |
| 700 } | 700 } |
| 701 | 701 |
| 702 | 702 |
| 703 void EffectGraphVisitor::VisitSwitchNode(SwitchNode* node) { | 703 void EffectGraphVisitor::VisitSwitchNode(SwitchNode* node) { |
| 704 Bailout("EffectGraphVisitor::VisitSwitchNode"); | 704 EffectGraphVisitor switch_body(owner(), temp_index()); |
| 705 node->body()->Visit(&switch_body); | |
| 706 Append(switch_body); | |
| 707 if ((node->label() != NULL) && (node->label()->join_for_break() != NULL)) { | |
| 708 if (is_open()) { | |
| 709 AddInstruction(node->label()->join_for_break()); | |
| 710 } else { | |
| 711 exit_ = node->label()->join_for_break(); | |
| 712 } | |
| 713 } | |
| 714 // No continue label allowed. | |
| 715 ASSERT((node->label() == NULL) || | |
| 716 (node->label()->join_for_continue() == NULL)); | |
| 705 } | 717 } |
| 706 | 718 |
| 707 | 719 |
| 720 // A case node contains zero or more case expressions, can contain default | |
| 721 // and a case statement body. | |
| 722 // Compose fragment as follows: | |
| 723 // - if no case expressions, must have default: | |
| 724 // a) target | |
| 725 // b) [ case-statements ] | |
| 726 // | |
| 727 // - if has 1 or more case statements | |
| 728 // a) target-0 | |
| 729 // b) [ case-expression-0 ] -> (true-target-0, target-1) | |
| 730 // c) target-1 | |
| 731 // d) [ case-expression-1 ] -> (true-target-1, exit-target) | |
| 732 // e) true-target-0 -> case-statements-join | |
| 733 // f) true-target-1 -> case-statements-join | |
| 734 // g) case-statements-join | |
| 735 // h) [ case-statements ] -> exit-join | |
| 736 // i) exit-target -> exit-join | |
| 737 // j) exit-join | |
| 738 // | |
| 739 // Note: The specification of switch/case is under discussion and may change | |
| 740 // drastically. | |
| 708 void EffectGraphVisitor::VisitCaseNode(CaseNode* node) { | 741 void EffectGraphVisitor::VisitCaseNode(CaseNode* node) { |
| 709 Bailout("EffectGraphVisitor::VisitCaseNode"); | 742 const intptr_t len = node->case_expressions()->length(); |
| 743 // Create case statements instructions. | |
| 744 const bool needs_join_at_statement_entry = | |
| 745 (len > 1) || ((len > 0) && (node->contains_default())); | |
| 746 EffectGraphVisitor for_case_statements(owner(), temp_index()); | |
| 747 // Compute start of statements fragment. | |
| 748 BlockEntryInstr* statement_start = NULL; | |
| 749 if ((node->label() != NULL) && (node->label()->is_continue_target())) { | |
| 750 // Since a labeled jump continue statement occur in a different case node, | |
| 751 // allocate JoinNode here and use it as statement start. | |
| 752 if (node->label()->join_for_continue() == NULL) { | |
| 753 node->label()->set_join_for_continue(new JoinEntryInstr()); | |
| 754 } | |
| 755 statement_start = node->label()->join_for_continue(); | |
| 756 } else if (needs_join_at_statement_entry) { | |
| 757 statement_start = new JoinEntryInstr(); | |
| 758 } else { | |
| 759 statement_start = new TargetEntryInstr(); | |
| 760 } | |
| 761 for_case_statements.AddInstruction(statement_start); | |
| 762 node->statements()->Visit(&for_case_statements); | |
| 763 if (is_open() && (len == 0)) { | |
| 764 ASSERT(node->contains_default()); | |
| 765 // Default only case node. | |
| 766 Append(for_case_statements); | |
| 767 return; | |
| 768 } | |
| 769 | |
| 770 // Generate instructions for all case expressions and collect data to | |
| 771 // connect them. | |
| 772 GrowableArray<TargetEntryInstr**> case_true_addresses; | |
| 773 GrowableArray<TargetEntryInstr**> case_false_addresses; | |
| 774 GrowableArray<TargetEntryInstr*> case_entries; | |
| 775 for (intptr_t i = 0; i < len; i++) { | |
| 776 AstNode* case_expr = node->case_expressions()->NodeAt(i); | |
| 777 TestGraphVisitor for_case_expression(owner(), temp_index()); | |
| 778 if (i == 0) { | |
| 779 case_entries.Add(NULL); // Not to be used | |
| 780 case_expr->Visit(&for_case_expression); | |
| 781 // Append only the first one, everything else is connected from it. | |
| 782 Append(for_case_expression); | |
| 783 } else { | |
| 784 TargetEntryInstr* case_entry_target = new TargetEntryInstr(); | |
| 785 case_entries.Add(case_entry_target); | |
| 786 for_case_expression.AddInstruction(case_entry_target); | |
| 787 case_expr->Visit(&for_case_expression); | |
| 788 } | |
| 789 case_true_addresses.Add(for_case_expression.true_successor_address()); | |
| 790 case_false_addresses.Add(for_case_expression.false_successor_address()); | |
| 791 } | |
| 792 | |
| 793 // Once a test fragment has been added, this fragment is closed. | |
| 794 ASSERT(!is_open()); | |
|
regis
2012/04/04 01:31:08
Can you move this ASSERT up inside the loop? Each
srdjan
2012/04/04 17:33:00
Discussed offline, leaving it here. Checking that
| |
| 795 | |
| 796 // Connect all test cases except the last one. | |
| 797 for (intptr_t i = 0; i < (len - 1); i++) { | |
| 798 ASSERT(needs_join_at_statement_entry); | |
| 799 *case_false_addresses[i] = case_entries[i + 1]; | |
| 800 TargetEntryInstr* true_target = new TargetEntryInstr(); | |
| 801 *case_true_addresses[i] = true_target; | |
| 802 true_target->SetSuccessor(statement_start); | |
| 803 } | |
| 804 | |
| 805 BlockEntryInstr* exit_instruction = NULL; | |
| 806 // Handle last (or only) case: false goes to exit or to statement if this | |
| 807 // node contains default. | |
| 808 if (len > 0) { | |
| 809 if (statement_start->IsTargetEntry()) { | |
| 810 *case_true_addresses[len - 1] = statement_start->AsTargetEntry(); | |
| 811 } else { | |
| 812 TargetEntryInstr* true_target = new TargetEntryInstr(); | |
| 813 *case_true_addresses[len - 1] = true_target; | |
| 814 true_target->SetSuccessor(statement_start); | |
| 815 } | |
| 816 TargetEntryInstr* false_target = new TargetEntryInstr(); | |
| 817 *case_false_addresses[len - 1] = false_target; | |
| 818 if (node->contains_default()) { | |
| 819 // True and false go to statement start. | |
| 820 false_target->SetSuccessor(statement_start); | |
| 821 if (for_case_statements.is_open()) { | |
| 822 exit_instruction = new TargetEntryInstr(); | |
| 823 for_case_statements.exit()->SetSuccessor(exit_instruction); | |
| 824 } | |
| 825 } else { | |
| 826 if (for_case_statements.is_open()) { | |
| 827 exit_instruction = new JoinEntryInstr(); | |
| 828 for_case_statements.exit()->SetSuccessor(exit_instruction); | |
| 829 } else { | |
| 830 exit_instruction = new TargetEntryInstr(); | |
| 831 } | |
| 832 false_target->SetSuccessor(exit_instruction); | |
| 833 } | |
| 834 } else { | |
| 835 // A CaseNode without case expressions must contain default. | |
| 836 ASSERT(node->contains_default()); | |
| 837 AddInstruction(statement_start); | |
| 838 } | |
| 839 | |
| 840 ASSERT(!is_open()); | |
| 841 exit_ = exit_instruction; | |
| 710 } | 842 } |
| 711 | 843 |
| 712 | 844 |
| 713 // <Statement> ::= While { label: SourceLabel | 845 // <Statement> ::= While { label: SourceLabel |
| 714 // condition: <Expression> | 846 // condition: <Expression> |
| 715 // body: <Sequence> } | 847 // body: <Sequence> } |
| 716 // The fragment is composed as follows: | 848 // The fragment is composed as follows: |
| 717 // a) continue-join (optional) | 849 // a) continue-join (optional) |
| 718 // b) loop-join | 850 // b) loop-join |
| 719 // c) [ test ] -> (body-entry-target, loop-exit-target) | 851 // c) [ test ] -> (body-entry-target, loop-exit-target) |
| (...skipping 1389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2109 char* chars = reinterpret_cast<char*>( | 2241 char* chars = reinterpret_cast<char*>( |
| 2110 Isolate::Current()->current_zone()->Allocate(len)); | 2242 Isolate::Current()->current_zone()->Allocate(len)); |
| 2111 OS::SNPrint(chars, len, kFormat, function_name, reason); | 2243 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 2112 const Error& error = Error::Handle( | 2244 const Error& error = Error::Handle( |
| 2113 LanguageError::New(String::Handle(String::New(chars)))); | 2245 LanguageError::New(String::Handle(String::New(chars)))); |
| 2114 Isolate::Current()->long_jump_base()->Jump(1, error); | 2246 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2115 } | 2247 } |
| 2116 | 2248 |
| 2117 | 2249 |
| 2118 } // namespace dart | 2250 } // namespace dart |
| OLD | NEW |