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 |