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 "lib/invocation_mirror.h" | 7 #include "lib/invocation_mirror.h" |
| 8 #include "vm/ast_printer.h" | 8 #include "vm/ast_printer.h" |
| 9 #include "vm/bit_vector.h" | 9 #include "vm/bit_vector.h" |
| 10 #include "vm/class_finalizer.h" | 10 #include "vm/class_finalizer.h" |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 35 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree."); | 35 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree."); |
| 36 DEFINE_FLAG(bool, print_scopes, false, "Print scopes of local variables."); | 36 DEFINE_FLAG(bool, print_scopes, false, "Print scopes of local variables."); |
| 37 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); | 37 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); |
| 38 DEFINE_FLAG(bool, print_flow_graph_optimized, false, | 38 DEFINE_FLAG(bool, print_flow_graph_optimized, false, |
| 39 "Print the IR flow graph when optimizing."); | 39 "Print the IR flow graph when optimizing."); |
| 40 DEFINE_FLAG(bool, trace_type_check_elimination, false, | 40 DEFINE_FLAG(bool, trace_type_check_elimination, false, |
| 41 "Trace type check elimination at compile time."); | 41 "Trace type check elimination at compile time."); |
| 42 DECLARE_FLAG(bool, enable_type_checks); | 42 DECLARE_FLAG(bool, enable_type_checks); |
| 43 | 43 |
| 44 | 44 |
| 45 JoinEntryInstr* NestedStatement::BreakTargetFor(SourceLabel* label) { | |
| 46 if (label != label_) return NULL; | |
| 47 if (break_target_ == NULL) { | |
| 48 break_target_ = | |
| 49 new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); | |
| 50 } | |
| 51 return break_target_; | |
| 52 } | |
| 53 | |
| 54 | |
| 55 JoinEntryInstr* NestedStatement::ContinueTargetFor(SourceLabel* label) { | |
| 56 return NULL; | |
| 57 } | |
| 58 | |
| 59 | |
| 60 // A nested statement that can be the target of a continue as well as a | |
| 61 // break. | |
| 62 class NestedLoop : public NestedStatement { | |
| 63 public: | |
| 64 NestedLoop(FlowGraphBuilder* owner, SourceLabel* label) | |
| 65 : NestedStatement(owner, label), continue_target_(NULL) { } | |
| 66 | |
| 67 JoinEntryInstr* continue_target() const { return continue_target_; } | |
| 68 | |
| 69 virtual JoinEntryInstr* ContinueTargetFor(SourceLabel* label); | |
| 70 | |
| 71 private: | |
| 72 JoinEntryInstr* continue_target_; | |
| 73 }; | |
| 74 | |
| 75 | |
| 76 JoinEntryInstr* NestedLoop::ContinueTargetFor(SourceLabel* label) { | |
| 77 if (label != this->label()) return NULL; | |
| 78 if (continue_target_ == NULL) { | |
| 79 continue_target_ = | |
| 80 new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); | |
| 81 } | |
| 82 return continue_target_; | |
| 83 } | |
| 84 | |
| 85 | |
| 86 // A nested switch which can be the target of a break if labeled, and whose | |
| 87 // cases can be the targets of continues. | |
| 88 class NestedSwitch : public NestedStatement { | |
| 89 public: | |
| 90 NestedSwitch(FlowGraphBuilder* owner, SwitchNode* node); | |
| 91 | |
| 92 virtual JoinEntryInstr* ContinueTargetFor(SourceLabel* label); | |
| 93 | |
| 94 private: | |
| 95 GrowableArray<SourceLabel*> case_labels_; | |
| 96 GrowableArray<JoinEntryInstr*> case_targets_; | |
| 97 }; | |
| 98 | |
| 99 | |
| 100 NestedSwitch::NestedSwitch(FlowGraphBuilder* owner, SwitchNode* node) | |
| 101 : NestedStatement(owner, node->label()), | |
| 102 case_labels_(node->body()->length()), | |
| 103 case_targets_(node->body()->length()) { | |
| 104 SequenceNode* body = node->body(); | |
| 105 for (intptr_t i = 0; i < body->length(); ++i) { | |
| 106 CaseNode* case_node = body->NodeAt(i)->AsCaseNode(); | |
| 107 if (case_node != NULL) { | |
| 108 case_labels_.Add(case_node->label()); | |
| 109 case_targets_.Add(NULL); | |
| 110 } | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 | |
| 115 JoinEntryInstr* NestedSwitch::ContinueTargetFor(SourceLabel* label) { | |
| 116 // Allocate a join for a case clause that matches the label. This block | |
| 117 // is not necessarily targeted by a continue, but we always use a join in | |
| 118 // the graph anyway. | |
| 119 for (intptr_t i = 0; i < case_labels_.length(); ++i) { | |
| 120 if (label != case_labels_[i]) continue; | |
| 121 if (case_targets_[i] == NULL) { | |
| 122 case_targets_[i] = | |
| 123 new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); | |
| 124 } | |
| 125 return case_targets_[i]; | |
| 126 } | |
| 127 return NULL; | |
| 128 } | |
| 129 | |
| 130 | |
| 45 FlowGraphBuilder::FlowGraphBuilder(ParsedFunction* parsed_function, | 131 FlowGraphBuilder::FlowGraphBuilder(ParsedFunction* parsed_function, |
| 46 const Array& ic_data_array, | 132 const Array& ic_data_array, |
| 47 InlineExitCollector* exit_collector, | 133 InlineExitCollector* exit_collector, |
| 48 intptr_t osr_id) | 134 intptr_t osr_id) |
| 49 : parsed_function_(parsed_function), | 135 : parsed_function_(parsed_function), |
| 50 ic_data_array_(ic_data_array), | 136 ic_data_array_(ic_data_array), |
| 51 num_copied_params_(parsed_function->num_copied_params()), | 137 num_copied_params_(parsed_function->num_copied_params()), |
| 52 // All parameters are copied if any parameter is. | 138 // All parameters are copied if any parameter is. |
| 53 num_non_copied_params_((num_copied_params_ == 0) | 139 num_non_copied_params_((num_copied_params_ == 0) |
| 54 ? parsed_function->function().num_fixed_parameters() | 140 ? parsed_function->function().num_fixed_parameters() |
| 55 : 0), | 141 : 0), |
| 56 num_stack_locals_(parsed_function->num_stack_locals()), | 142 num_stack_locals_(parsed_function->num_stack_locals()), |
| 57 exit_collector_(exit_collector), | 143 exit_collector_(exit_collector), |
| 58 guarded_fields_(new ZoneGrowableArray<const Field*>()), | 144 guarded_fields_(new ZoneGrowableArray<const Field*>()), |
| 59 last_used_block_id_(0), // 0 is used for the graph entry. | 145 last_used_block_id_(0), // 0 is used for the graph entry. |
| 60 context_level_(0), | 146 context_level_(0), |
| 61 try_index_(CatchClauseNode::kInvalidTryIndex), | 147 try_index_(CatchClauseNode::kInvalidTryIndex), |
| 62 catch_try_index_(CatchClauseNode::kInvalidTryIndex), | 148 catch_try_index_(CatchClauseNode::kInvalidTryIndex), |
| 63 loop_depth_(0), | 149 loop_depth_(0), |
| 64 graph_entry_(NULL), | 150 graph_entry_(NULL), |
| 65 temp_count_(0), | 151 temp_count_(0), |
| 66 args_pushed_(0), | 152 args_pushed_(0), |
| 153 nesting_stack_(NULL), | |
| 67 osr_id_(osr_id) { } | 154 osr_id_(osr_id) { } |
| 68 | 155 |
| 69 | 156 |
| 70 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) { | 157 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) { |
| 71 graph_entry_->AddCatchEntry(entry); | 158 graph_entry_->AddCatchEntry(entry); |
| 72 } | 159 } |
| 73 | 160 |
| 74 | 161 |
| 75 void InlineExitCollector::PrepareGraphs(FlowGraph* callee_graph) { | 162 void InlineExitCollector::PrepareGraphs(FlowGraph* callee_graph) { |
| 76 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); | 163 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); |
| (...skipping 1483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1560 | 1647 |
| 1561 node->true_branch()->Visit(&for_true); | 1648 node->true_branch()->Visit(&for_true); |
| 1562 // The for_false graph fragment will be empty (default graph fragment) if | 1649 // The for_false graph fragment will be empty (default graph fragment) if |
| 1563 // we do not call Visit. | 1650 // we do not call Visit. |
| 1564 if (node->false_branch() != NULL) node->false_branch()->Visit(&for_false); | 1651 if (node->false_branch() != NULL) node->false_branch()->Visit(&for_false); |
| 1565 Join(for_test, for_true, for_false); | 1652 Join(for_test, for_true, for_false); |
| 1566 } | 1653 } |
| 1567 | 1654 |
| 1568 | 1655 |
| 1569 void EffectGraphVisitor::VisitSwitchNode(SwitchNode* node) { | 1656 void EffectGraphVisitor::VisitSwitchNode(SwitchNode* node) { |
| 1657 NestedSwitch nested_switch(owner(), node); | |
| 1570 EffectGraphVisitor switch_body(owner()); | 1658 EffectGraphVisitor switch_body(owner()); |
| 1571 node->body()->Visit(&switch_body); | 1659 node->body()->Visit(&switch_body); |
| 1572 Append(switch_body); | 1660 Append(switch_body); |
| 1573 if ((node->label() != NULL) && (node->label()->join_for_break() != NULL)) { | 1661 if (nested_switch.break_target() != NULL) { |
| 1574 if (is_open()) Goto(node->label()->join_for_break()); | 1662 if (is_open()) Goto(nested_switch.break_target()); |
| 1575 exit_ = node->label()->join_for_break(); | 1663 exit_ = nested_switch.break_target(); |
| 1576 } | 1664 } |
| 1577 // No continue label allowed. | |
| 1578 ASSERT((node->label() == NULL) || | |
| 1579 (node->label()->join_for_continue() == NULL)); | |
| 1580 } | 1665 } |
| 1581 | 1666 |
| 1582 | 1667 |
| 1583 // A case node contains zero or more case expressions, can contain default | 1668 // A case node contains zero or more case expressions, can contain default |
| 1584 // and a case statement body. | 1669 // and a case statement body. |
| 1585 // Compose fragment as follows: | 1670 // Compose fragment as follows: |
| 1586 // - if no case expressions, must have default: | 1671 // - if no case expressions, must have default: |
| 1587 // a) target | 1672 // a) target |
| 1588 // b) [ case-statements ] | 1673 // b) [ case-statements ] |
| 1589 // | 1674 // |
| 1590 // - if has 1 or more case statements | 1675 // - if has 1 or more case statements |
| 1591 // a) target-0 | 1676 // a) target-0 |
| 1592 // b) [ case-expression-0 ] -> (true-target-0, target-1) | 1677 // b) [ case-expression-0 ] -> (true-target-0, target-1) |
| 1593 // c) target-1 | 1678 // c) target-1 |
| 1594 // d) [ case-expression-1 ] -> (true-target-1, exit-target) | 1679 // d) [ case-expression-1 ] -> (true-target-1, exit-target) |
| 1595 // e) true-target-0 -> case-statements-join | 1680 // e) true-target-0 -> case-statements-join |
| 1596 // f) true-target-1 -> case-statements-join | 1681 // f) true-target-1 -> case-statements-join |
| 1597 // g) case-statements-join | 1682 // g) case-statements-join |
| 1598 // h) [ case-statements ] -> exit-join | 1683 // h) [ case-statements ] -> exit-join |
| 1599 // i) exit-target -> exit-join | 1684 // i) exit-target -> exit-join |
| 1600 // j) exit-join | 1685 // j) exit-join |
| 1601 // | 1686 // |
| 1602 // Note: The specification of switch/case is under discussion and may change | 1687 // Note: The specification of switch/case is under discussion and may change |
| 1603 // drastically. | 1688 // drastically. |
| 1604 void EffectGraphVisitor::VisitCaseNode(CaseNode* node) { | 1689 void EffectGraphVisitor::VisitCaseNode(CaseNode* node) { |
| 1605 const intptr_t len = node->case_expressions()->length(); | 1690 const intptr_t len = node->case_expressions()->length(); |
| 1606 // Create case statements instructions. | 1691 // Create case statements instructions. |
| 1607 EffectGraphVisitor for_case_statements(owner()); | 1692 EffectGraphVisitor for_case_statements(owner()); |
| 1608 // Compute start of statements fragment. | 1693 // Compute the start of the statements fragment. |
| 1609 JoinEntryInstr* statement_start = NULL; | 1694 JoinEntryInstr* statement_start = NULL; |
| 1610 if ((node->label() != NULL) && node->label()->is_continue_target()) { | 1695 if (node->label() == NULL) { |
| 1611 // Since a labeled jump continue statement occur in a different case node, | |
| 1612 // allocate JoinNode here and use it as statement start. | |
| 1613 statement_start = node->label()->join_for_continue(); | |
| 1614 if (statement_start == NULL) { | |
| 1615 statement_start = new JoinEntryInstr(owner()->AllocateBlockId(), | |
| 1616 owner()->try_index()); | |
| 1617 node->label()->set_join_for_continue(statement_start); | |
| 1618 } | |
| 1619 } else { | |
| 1620 statement_start = new JoinEntryInstr(owner()->AllocateBlockId(), | 1696 statement_start = new JoinEntryInstr(owner()->AllocateBlockId(), |
| 1621 owner()->try_index()); | 1697 owner()->try_index()); |
| 1698 } else { | |
| 1699 // The case nodes are nested inside a SequenceNode that is the body of a | |
| 1700 // SwitchNode. The SwitchNode on the nesting stack contains the | |
| 1701 // continue labels for all the case clauses. | |
| 1702 statement_start = | |
| 1703 owner()->nesting_stack()->outer()->ContinueTargetFor(node->label()); | |
| 1622 } | 1704 } |
| 1705 ASSERT(statement_start != NULL); | |
| 1623 node->statements()->Visit(&for_case_statements); | 1706 node->statements()->Visit(&for_case_statements); |
| 1624 Instruction* statement_exit = | 1707 Instruction* statement_exit = |
| 1625 AppendFragment(statement_start, for_case_statements); | 1708 AppendFragment(statement_start, for_case_statements); |
| 1626 if (is_open() && (len == 0)) { | 1709 if (is_open() && (len == 0)) { |
| 1627 ASSERT(node->contains_default()); | 1710 ASSERT(node->contains_default()); |
| 1628 // Default only case node. | 1711 // Default only case node. |
| 1629 Goto(statement_start); | 1712 Goto(statement_start); |
| 1630 exit_ = statement_exit; | 1713 exit_ = statement_exit; |
| 1631 return; | 1714 return; |
| 1632 } | 1715 } |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1688 // body: <Sequence> } | 1771 // body: <Sequence> } |
| 1689 // The fragment is composed as follows: | 1772 // The fragment is composed as follows: |
| 1690 // a) loop-join | 1773 // a) loop-join |
| 1691 // b) [ test ] -> (body-entry-target, loop-exit-target) | 1774 // b) [ test ] -> (body-entry-target, loop-exit-target) |
| 1692 // c) body-entry-target | 1775 // c) body-entry-target |
| 1693 // d) [ body ] -> (continue-join) | 1776 // d) [ body ] -> (continue-join) |
| 1694 // e) continue-join -> (loop-join) | 1777 // e) continue-join -> (loop-join) |
| 1695 // f) loop-exit-target | 1778 // f) loop-exit-target |
| 1696 // g) break-join (optional) | 1779 // g) break-join (optional) |
| 1697 void EffectGraphVisitor::VisitWhileNode(WhileNode* node) { | 1780 void EffectGraphVisitor::VisitWhileNode(WhileNode* node) { |
| 1781 NestedLoop nested_loop(owner(), node->label()); | |
| 1698 owner()->IncrementLoopDepth(); | 1782 owner()->IncrementLoopDepth(); |
| 1783 | |
| 1699 TestGraphVisitor for_test(owner(), node->condition()->token_pos()); | 1784 TestGraphVisitor for_test(owner(), node->condition()->token_pos()); |
| 1700 node->condition()->Visit(&for_test); | 1785 node->condition()->Visit(&for_test); |
| 1701 ASSERT(!for_test.is_empty()); // Language spec. | 1786 ASSERT(!for_test.is_empty()); // Language spec. |
| 1702 | 1787 |
| 1703 EffectGraphVisitor for_body(owner()); | 1788 EffectGraphVisitor for_body(owner()); |
| 1704 node->body()->Visit(&for_body); | 1789 node->body()->Visit(&for_body); |
| 1705 | 1790 |
| 1706 // Labels are set after body traversal. | 1791 // Labels are set after body traversal. |
| 1707 SourceLabel* lbl = node->label(); | 1792 JoinEntryInstr* join = nested_loop.continue_target(); |
| 1708 ASSERT(lbl != NULL); | |
| 1709 JoinEntryInstr* join = lbl->join_for_continue(); | |
| 1710 if (join != NULL) { | 1793 if (join != NULL) { |
| 1711 if (for_body.is_open()) for_body.Goto(join); | 1794 if (for_body.is_open()) for_body.Goto(join); |
| 1712 for_body.exit_ = join; | 1795 for_body.exit_ = join; |
| 1713 } | 1796 } |
| 1714 TieLoop(node->token_pos(), for_test, for_body); | 1797 TieLoop(node->token_pos(), for_test, for_body); |
| 1715 join = lbl->join_for_break(); | 1798 join = nested_loop.break_target(); |
| 1716 if (join != NULL) { | 1799 if (join != NULL) { |
| 1717 Goto(join); | 1800 Goto(join); |
| 1718 exit_ = join; | 1801 exit_ = join; |
| 1719 } | 1802 } |
| 1720 owner()->DecrementLoopDepth(); | 1803 owner()->DecrementLoopDepth(); |
| 1721 } | 1804 } |
| 1722 | 1805 |
| 1723 | 1806 |
| 1724 // The fragment is composed as follows: | 1807 // The fragment is composed as follows: |
| 1725 // a) body-entry-join | 1808 // a) body-entry-join |
| 1726 // b) [ body ] | 1809 // b) [ body ] |
| 1727 // c) test-entry (continue-join or body-exit-target) | 1810 // c) test-entry (continue-join or body-exit-target) |
| 1728 // d) [ test-entry ] -> (back-target, loop-exit-target) | 1811 // d) [ test-entry ] -> (back-target, loop-exit-target) |
| 1729 // e) back-target -> (body-entry-join) | 1812 // e) back-target -> (body-entry-join) |
| 1730 // f) loop-exit-target | 1813 // f) loop-exit-target |
| 1731 // g) break-join | 1814 // g) break-join |
| 1732 void EffectGraphVisitor::VisitDoWhileNode(DoWhileNode* node) { | 1815 void EffectGraphVisitor::VisitDoWhileNode(DoWhileNode* node) { |
| 1816 NestedLoop nested_loop(owner(), node->label()); | |
| 1733 owner()->IncrementLoopDepth(); | 1817 owner()->IncrementLoopDepth(); |
| 1734 // Traverse body first in order to generate continue and break labels. | 1818 |
| 1819 // Traverse the body first in order to generate continue and break labels. | |
| 1735 EffectGraphVisitor for_body(owner()); | 1820 EffectGraphVisitor for_body(owner()); |
| 1736 node->body()->Visit(&for_body); | 1821 node->body()->Visit(&for_body); |
| 1737 | 1822 |
| 1738 TestGraphVisitor for_test(owner(), node->condition()->token_pos()); | 1823 TestGraphVisitor for_test(owner(), node->condition()->token_pos()); |
| 1739 node->condition()->Visit(&for_test); | 1824 node->condition()->Visit(&for_test); |
| 1740 ASSERT(is_open()); | 1825 ASSERT(is_open()); |
| 1741 | 1826 |
| 1742 // Tie do-while loop (test is after the body). | 1827 // Tie do-while loop (test is after the body). |
| 1743 JoinEntryInstr* body_entry_join = | 1828 JoinEntryInstr* body_entry_join = |
| 1744 new JoinEntryInstr(owner()->AllocateBlockId(), | 1829 new JoinEntryInstr(owner()->AllocateBlockId(), |
| 1745 owner()->try_index()); | 1830 owner()->try_index()); |
| 1746 Goto(body_entry_join); | 1831 Goto(body_entry_join); |
| 1747 Instruction* body_exit = AppendFragment(body_entry_join, for_body); | 1832 Instruction* body_exit = AppendFragment(body_entry_join, for_body); |
| 1748 | 1833 |
| 1749 JoinEntryInstr* join = node->label()->join_for_continue(); | 1834 JoinEntryInstr* join = nested_loop.continue_target(); |
| 1750 if ((body_exit != NULL) || (join != NULL)) { | 1835 if ((body_exit != NULL) || (join != NULL)) { |
| 1751 if (join == NULL) { | 1836 if (join == NULL) { |
| 1752 join = new JoinEntryInstr(owner()->AllocateBlockId(), | 1837 join = new JoinEntryInstr(owner()->AllocateBlockId(), |
| 1753 owner()->try_index()); | 1838 owner()->try_index()); |
| 1754 } | 1839 } |
| 1755 CheckStackOverflowInstr* check = | 1840 CheckStackOverflowInstr* check = |
| 1756 new CheckStackOverflowInstr(node->token_pos(), owner()->loop_depth()); | 1841 new CheckStackOverflowInstr(node->token_pos(), owner()->loop_depth()); |
| 1757 join->LinkTo(check); | 1842 join->LinkTo(check); |
| 1758 check->LinkTo(for_test.entry()); | 1843 check->LinkTo(for_test.entry()); |
| 1759 if (body_exit != NULL) { | 1844 if (body_exit != NULL) { |
| 1760 body_exit->Goto(join); | 1845 body_exit->Goto(join); |
| 1761 } | 1846 } |
| 1762 } | 1847 } |
| 1763 | 1848 |
| 1764 for_test.IfTrueGoto(body_entry_join); | 1849 for_test.IfTrueGoto(body_entry_join); |
| 1765 join = node->label()->join_for_break(); | 1850 join = nested_loop.break_target(); |
| 1766 if (join == NULL) { | 1851 if (join == NULL) { |
| 1767 exit_ = for_test.CreateFalseSuccessor(); | 1852 exit_ = for_test.CreateFalseSuccessor(); |
| 1768 } else { | 1853 } else { |
| 1769 for_test.IfFalseGoto(join); | 1854 for_test.IfFalseGoto(join); |
| 1770 exit_ = join; | 1855 exit_ = join; |
| 1771 } | 1856 } |
| 1772 owner()->DecrementLoopDepth(); | 1857 owner()->DecrementLoopDepth(); |
| 1773 } | 1858 } |
| 1774 | 1859 |
| 1775 | 1860 |
| 1776 // A ForNode can contain break and continue jumps. 'break' joins to | 1861 // A ForNode can contain break and continue jumps. 'break' joins to |
| 1777 // ForNode exit, 'continue' joins at increment entry. The fragment is composed | 1862 // ForNode exit, 'continue' joins at increment entry. The fragment is composed |
| 1778 // as follows: | 1863 // as follows: |
| 1779 // a) [ initializer ] | 1864 // a) [ initializer ] |
| 1780 // b) loop-join | 1865 // b) loop-join |
| 1781 // c) [ test ] -> (body-entry-target, loop-exit-target) | 1866 // c) [ test ] -> (body-entry-target, loop-exit-target) |
| 1782 // d) body-entry-target | 1867 // d) body-entry-target |
| 1783 // e) [ body ] | 1868 // e) [ body ] |
| 1784 // f) continue-join (optional) | 1869 // f) continue-join (optional) |
| 1785 // g) [ increment ] -> (loop-join) | 1870 // g) [ increment ] -> (loop-join) |
| 1786 // h) loop-exit-target | 1871 // h) loop-exit-target |
| 1787 // i) break-join | 1872 // i) break-join |
| 1788 void EffectGraphVisitor::VisitForNode(ForNode* node) { | 1873 void EffectGraphVisitor::VisitForNode(ForNode* node) { |
| 1789 EffectGraphVisitor for_initializer(owner()); | 1874 EffectGraphVisitor for_initializer(owner()); |
| 1790 node->initializer()->Visit(&for_initializer); | 1875 node->initializer()->Visit(&for_initializer); |
| 1791 Append(for_initializer); | 1876 Append(for_initializer); |
| 1792 ASSERT(is_open()); | 1877 ASSERT(is_open()); |
| 1793 | 1878 |
| 1879 NestedLoop nested_loop(owner(), node->label()); | |
| 1794 owner()->IncrementLoopDepth(); | 1880 owner()->IncrementLoopDepth(); |
| 1795 // Compose body to set any jump labels. | 1881 // Compose body to set any jump labels. |
| 1796 EffectGraphVisitor for_body(owner()); | 1882 EffectGraphVisitor for_body(owner()); |
| 1797 node->body()->Visit(&for_body); | 1883 node->body()->Visit(&for_body); |
| 1798 | 1884 |
| 1799 EffectGraphVisitor for_increment(owner()); | 1885 EffectGraphVisitor for_increment(owner()); |
| 1800 node->increment()->Visit(&for_increment); | 1886 node->increment()->Visit(&for_increment); |
| 1801 | 1887 |
| 1802 // Join the loop body and increment and then tie the loop. | 1888 // Join the loop body and increment and then tie the loop. |
| 1803 JoinEntryInstr* continue_join = node->label()->join_for_continue(); | 1889 JoinEntryInstr* continue_join = nested_loop.continue_target(); |
| 1804 if ((continue_join != NULL) || for_body.is_open()) { | 1890 if ((continue_join != NULL) || for_body.is_open()) { |
| 1805 JoinEntryInstr* loop_entry = | 1891 JoinEntryInstr* loop_entry = |
| 1806 new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); | 1892 new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); |
| 1807 if (continue_join != NULL) { | 1893 if (continue_join != NULL) { |
| 1808 if (for_body.is_open()) for_body.Goto(continue_join); | 1894 if (for_body.is_open()) for_body.Goto(continue_join); |
| 1809 Instruction* current = AppendFragment(continue_join, for_increment); | 1895 Instruction* current = AppendFragment(continue_join, for_increment); |
| 1810 current->Goto(loop_entry); | 1896 current->Goto(loop_entry); |
| 1811 } else { | 1897 } else { |
| 1812 for_body.Append(for_increment); | 1898 for_body.Append(for_increment); |
| 1813 for_body.Goto(loop_entry); | 1899 for_body.Goto(loop_entry); |
| 1814 } | 1900 } |
| 1815 Goto(loop_entry); | 1901 Goto(loop_entry); |
| 1816 exit_ = loop_entry; | 1902 exit_ = loop_entry; |
| 1817 AddInstruction( | 1903 AddInstruction( |
| 1818 new CheckStackOverflowInstr(node->token_pos(), owner()->loop_depth())); | 1904 new CheckStackOverflowInstr(node->token_pos(), owner()->loop_depth())); |
| 1819 } | 1905 } |
| 1820 | 1906 |
| 1821 if (node->condition() == NULL) { | 1907 if (node->condition() == NULL) { |
| 1822 // Endless loop, no test. | 1908 // Endless loop, no test. |
| 1823 Append(for_body); | 1909 Append(for_body); |
| 1824 exit_ = node->label()->join_for_break(); // May be NULL. | 1910 exit_ = nested_loop.break_target(); // May be NULL. |
| 1825 } else { | 1911 } else { |
| 1826 TestGraphVisitor for_test(owner(), node->condition()->token_pos()); | 1912 TestGraphVisitor for_test(owner(), node->condition()->token_pos()); |
| 1827 node->condition()->Visit(&for_test); | 1913 node->condition()->Visit(&for_test); |
| 1828 Append(for_test); | 1914 Append(for_test); |
| 1829 | 1915 |
| 1830 BlockEntryInstr* body_entry = for_test.CreateTrueSuccessor(); | 1916 BlockEntryInstr* body_entry = for_test.CreateTrueSuccessor(); |
| 1831 AppendFragment(body_entry, for_body); | 1917 AppendFragment(body_entry, for_body); |
| 1832 | 1918 |
| 1833 if (node->label()->join_for_break() == NULL) { | 1919 if (nested_loop.break_target() == NULL) { |
| 1834 exit_ = for_test.CreateFalseSuccessor(); | 1920 exit_ = for_test.CreateFalseSuccessor(); |
| 1835 } else { | 1921 } else { |
| 1836 for_test.IfFalseGoto(node->label()->join_for_break()); | 1922 for_test.IfFalseGoto(nested_loop.break_target()); |
| 1837 exit_ = node->label()->join_for_break(); | 1923 exit_ = nested_loop.break_target(); |
| 1838 } | 1924 } |
| 1839 } | 1925 } |
| 1840 owner()->DecrementLoopDepth(); | 1926 owner()->DecrementLoopDepth(); |
| 1841 } | 1927 } |
| 1842 | 1928 |
| 1843 | 1929 |
| 1844 void EffectGraphVisitor::VisitJumpNode(JumpNode* node) { | 1930 void EffectGraphVisitor::VisitJumpNode(JumpNode* node) { |
| 1845 for (intptr_t i = 0; i < node->inlined_finally_list_length(); i++) { | 1931 for (intptr_t i = 0; i < node->inlined_finally_list_length(); i++) { |
| 1846 EffectGraphVisitor for_effect(owner()); | 1932 EffectGraphVisitor for_effect(owner()); |
| 1847 node->InlinedFinallyNodeAt(i)->Visit(&for_effect); | 1933 node->InlinedFinallyNodeAt(i)->Visit(&for_effect); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 1871 } | 1957 } |
| 1872 } | 1958 } |
| 1873 ASSERT(target_context_level >= 0); | 1959 ASSERT(target_context_level >= 0); |
| 1874 intptr_t current_context_level = owner()->context_level(); | 1960 intptr_t current_context_level = owner()->context_level(); |
| 1875 ASSERT(current_context_level >= target_context_level); | 1961 ASSERT(current_context_level >= target_context_level); |
| 1876 while (current_context_level-- > target_context_level) { | 1962 while (current_context_level-- > target_context_level) { |
| 1877 UnchainContext(); | 1963 UnchainContext(); |
| 1878 } | 1964 } |
| 1879 | 1965 |
| 1880 JoinEntryInstr* jump_target = NULL; | 1966 JoinEntryInstr* jump_target = NULL; |
| 1881 if (node->kind() == Token::kBREAK) { | 1967 if (node->kind() == Token::kBREAK) { |
|
Florian Schneider
2013/11/13 17:42:58
For less duplicated code maybe move this condition
Kevin Millikin (Google)
2013/11/13 17:47:22
That sounds good to me. I'll do it.
| |
| 1882 if (node->label()->join_for_break() == NULL) { | 1968 NestedStatement* current = owner()->nesting_stack(); |
| 1883 node->label()->set_join_for_break( | 1969 while (current != NULL) { |
| 1884 new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index())); | 1970 jump_target = current->BreakTargetFor(node->label()); |
| 1971 if (jump_target != NULL) break; | |
| 1972 current = current->outer(); | |
| 1885 } | 1973 } |
| 1886 jump_target = node->label()->join_for_break(); | |
| 1887 } else { | 1974 } else { |
| 1888 if (node->label()->join_for_continue() == NULL) { | 1975 NestedStatement* current = owner()->nesting_stack(); |
| 1889 node->label()->set_join_for_continue( | 1976 while (current != NULL) { |
| 1890 new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index())); | 1977 jump_target = current->ContinueTargetFor(node->label()); |
| 1978 if (jump_target != NULL) break; | |
| 1979 current = current->outer(); | |
| 1891 } | 1980 } |
| 1892 jump_target = node->label()->join_for_continue(); | |
| 1893 } | 1981 } |
| 1982 ASSERT(jump_target != NULL); | |
| 1894 Goto(jump_target); | 1983 Goto(jump_target); |
| 1895 } | 1984 } |
| 1896 | 1985 |
| 1897 | 1986 |
| 1898 void EffectGraphVisitor::VisitArgumentListNode(ArgumentListNode* node) { | 1987 void EffectGraphVisitor::VisitArgumentListNode(ArgumentListNode* node) { |
| 1899 UNREACHABLE(); | 1988 UNREACHABLE(); |
| 1900 } | 1989 } |
| 1901 | 1990 |
| 1902 | 1991 |
| 1903 intptr_t EffectGraphVisitor::GetCurrentTempLocalIndex() const { | 1992 intptr_t EffectGraphVisitor::GetCurrentTempLocalIndex() const { |
| (...skipping 1475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3379 | 3468 |
| 3380 | 3469 |
| 3381 // <Statement> ::= Sequence { scope: LocalScope | 3470 // <Statement> ::= Sequence { scope: LocalScope |
| 3382 // nodes: <Statement>* | 3471 // nodes: <Statement>* |
| 3383 // label: SourceLabel } | 3472 // label: SourceLabel } |
| 3384 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { | 3473 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { |
| 3385 LocalScope* scope = node->scope(); | 3474 LocalScope* scope = node->scope(); |
| 3386 const intptr_t num_context_variables = | 3475 const intptr_t num_context_variables = |
| 3387 (scope != NULL) ? scope->num_context_variables() : 0; | 3476 (scope != NULL) ? scope->num_context_variables() : 0; |
| 3388 int previous_context_level = owner()->context_level(); | 3477 int previous_context_level = owner()->context_level(); |
| 3478 // The outermost function sequence cannot contain a label. | |
| 3479 ASSERT((node->label() == NULL) || | |
| 3480 (node != owner()->parsed_function()->node_sequence())); | |
| 3481 NestedStatement nested_block(owner(), node->label()); | |
| 3482 | |
| 3389 if (num_context_variables > 0) { | 3483 if (num_context_variables > 0) { |
| 3390 // The loop local scope declares variables that are captured. | 3484 // The loop local scope declares variables that are captured. |
| 3391 // Allocate and chain a new context. | 3485 // Allocate and chain a new context. |
| 3392 // Allocate context computation (uses current CTX) | 3486 // Allocate context computation (uses current CTX) |
| 3393 Value* allocated_context = | 3487 Value* allocated_context = |
| 3394 Bind(new AllocateContextInstr(node->token_pos(), | 3488 Bind(new AllocateContextInstr(node->token_pos(), |
| 3395 num_context_variables)); | 3489 num_context_variables)); |
| 3396 { LocalVariable* tmp_var = EnterTempLocalScope(allocated_context); | 3490 { LocalVariable* tmp_var = EnterTempLocalScope(allocated_context); |
| 3397 // If this node_sequence is the body of the function being compiled, and | 3491 // If this node_sequence is the body of the function being compiled, and |
| 3398 // if this function allocates context variables, but none of its enclosing | 3492 // if this function allocates context variables, but none of its enclosing |
| 3399 // functions do, the context on entry is not linked as parent of the | 3493 // functions do, the context on entry is not linked as parent of the |
| 3400 // allocated context but saved on entry and restored on exit as to prevent | 3494 // allocated context but saved on entry and restored on exit as to prevent |
| 3401 // memory leaks. | 3495 // memory leaks. |
| 3402 // In this case, the parser pre-allocates a variable to save the context. | 3496 // In this case, the parser pre-allocates a variable to save the context. |
| 3403 if (MustSaveRestoreContext(node)) { | 3497 if (MustSaveRestoreContext(node)) { |
| 3404 BuildSaveContext( | 3498 BuildSaveContext( |
| 3405 *owner()->parsed_function()->saved_entry_context_var()); | 3499 *owner()->parsed_function()->saved_entry_context_var()); |
| 3406 Value* null_context = Bind(new ConstantInstr(Object::ZoneHandle())); | 3500 Value* null_context = Bind(new ConstantInstr(Object::ZoneHandle())); |
| 3407 AddInstruction(new StoreContextInstr(null_context)); | 3501 AddInstruction(new StoreContextInstr(null_context)); |
| 3408 } | 3502 } |
| 3409 Value* current_context = Bind(new CurrentContextInstr()); | 3503 Value* current_context = Bind(new CurrentContextInstr()); |
| 3410 Value* tmp_val = Bind(new LoadLocalInstr(*tmp_var)); | 3504 Value* tmp_val = Bind(new LoadLocalInstr(*tmp_var)); |
| 3411 Do(new StoreVMFieldInstr(tmp_val, | 3505 Do(new StoreVMFieldInstr(tmp_val, |
| 3412 Context::parent_offset(), | 3506 Context::parent_offset(), |
| 3413 current_context, | 3507 current_context, |
| 3414 Type::ZoneHandle())); | 3508 Type::ZoneHandle())); |
| 3415 AddInstruction( | 3509 AddInstruction( |
| 3416 new StoreContextInstr(Bind(ExitTempLocalScope(tmp_var)))); | 3510 new StoreContextInstr(Bind(ExitTempLocalScope(tmp_var)))); |
| 3417 } | 3511 } |
| 3512 | |
| 3418 owner()->set_context_level(scope->context_level()); | 3513 owner()->set_context_level(scope->context_level()); |
| 3419 | 3514 |
| 3420 // If this node_sequence is the body of the function being compiled, copy | 3515 // If this node_sequence is the body of the function being compiled, copy |
| 3421 // the captured parameters from the frame into the context. | 3516 // the captured parameters from the frame into the context. |
| 3422 if (node == owner()->parsed_function()->node_sequence()) { | 3517 if (node == owner()->parsed_function()->node_sequence()) { |
| 3423 ASSERT(scope->context_level() == 1); | 3518 ASSERT(scope->context_level() == 1); |
| 3424 const Function& function = owner()->parsed_function()->function(); | 3519 const Function& function = owner()->parsed_function()->function(); |
| 3425 const int num_params = function.NumParameters(); | 3520 const int num_params = function.NumParameters(); |
| 3426 int param_frame_index = (num_params == function.num_fixed_parameters()) ? | 3521 int param_frame_index = (num_params == function.num_fixed_parameters()) ? |
| 3427 (kParamEndSlotFromFp + num_params) : kFirstLocalSlotFromFp; | 3522 (kParamEndSlotFromFp + num_params) : kFirstLocalSlotFromFp; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3502 if (is_open()) { | 3597 if (is_open()) { |
| 3503 if (MustSaveRestoreContext(node)) { | 3598 if (MustSaveRestoreContext(node)) { |
| 3504 ASSERT(num_context_variables > 0); | 3599 ASSERT(num_context_variables > 0); |
| 3505 BuildRestoreContext( | 3600 BuildRestoreContext( |
| 3506 *owner()->parsed_function()->saved_entry_context_var()); | 3601 *owner()->parsed_function()->saved_entry_context_var()); |
| 3507 } else if (num_context_variables > 0) { | 3602 } else if (num_context_variables > 0) { |
| 3508 UnchainContext(); | 3603 UnchainContext(); |
| 3509 } | 3604 } |
| 3510 } | 3605 } |
| 3511 | 3606 |
| 3512 // No continue on sequence allowed. | |
| 3513 ASSERT((node->label() == NULL) || | |
| 3514 (node->label()->join_for_continue() == NULL)); | |
| 3515 // If this node sequence is labeled, a break out of the sequence will have | 3607 // If this node sequence is labeled, a break out of the sequence will have |
| 3516 // taken care of unchaining the context. | 3608 // taken care of unchaining the context. |
| 3517 if ((node->label() != NULL) && | 3609 if (nested_block.break_target() != NULL) { |
| 3518 (node->label()->join_for_break() != NULL)) { | 3610 if (is_open()) Goto(nested_block.break_target()); |
| 3519 if (is_open()) Goto(node->label()->join_for_break()); | 3611 exit_ = nested_block.break_target(); |
| 3520 exit_ = node->label()->join_for_break(); | |
| 3521 } | 3612 } |
| 3522 | 3613 |
| 3523 // The outermost function sequence cannot contain a label. | |
| 3524 ASSERT((node->label() == NULL) || | |
| 3525 (node != owner()->parsed_function()->node_sequence())); | |
| 3526 owner()->set_context_level(previous_context_level); | 3614 owner()->set_context_level(previous_context_level); |
| 3527 } | 3615 } |
| 3528 | 3616 |
| 3529 | 3617 |
| 3530 void EffectGraphVisitor::VisitCatchClauseNode(CatchClauseNode* node) { | 3618 void EffectGraphVisitor::VisitCatchClauseNode(CatchClauseNode* node) { |
| 3531 InlineBailout("EffectGraphVisitor::VisitCatchClauseNode (exception)"); | 3619 InlineBailout("EffectGraphVisitor::VisitCatchClauseNode (exception)"); |
| 3532 // Restores CTX from local variable ':saved_context'. | 3620 // Restores CTX from local variable ':saved_context'. |
| 3533 BuildRestoreContext(node->context_var()); | 3621 BuildRestoreContext(node->context_var()); |
| 3534 | 3622 |
| 3535 EffectGraphVisitor for_catch(owner()); | 3623 EffectGraphVisitor for_catch(owner()); |
| (...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3886 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | 3974 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
| 3887 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 3975 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
| 3888 OS::SNPrint(chars, len, kFormat, function_name, reason); | 3976 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 3889 const Error& error = Error::Handle( | 3977 const Error& error = Error::Handle( |
| 3890 LanguageError::New(String::Handle(String::New(chars)))); | 3978 LanguageError::New(String::Handle(String::New(chars)))); |
| 3891 Isolate::Current()->long_jump_base()->Jump(1, error); | 3979 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 3892 } | 3980 } |
| 3893 | 3981 |
| 3894 | 3982 |
| 3895 } // namespace dart | 3983 } // namespace dart |
| OLD | NEW |