| 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/code_descriptors.h" | 10 #include "vm/code_descriptors.h" |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 // All parameters are copied if any parameter is. | 52 // All parameters are copied if any parameter is. |
| 53 num_non_copied_params_((num_copied_params_ == 0) | 53 num_non_copied_params_((num_copied_params_ == 0) |
| 54 ? parsed_function->function().num_fixed_parameters() | 54 ? parsed_function->function().num_fixed_parameters() |
| 55 : 0), | 55 : 0), |
| 56 num_stack_locals_(parsed_function->num_stack_locals()), | 56 num_stack_locals_(parsed_function->num_stack_locals()), |
| 57 exit_collector_(exit_collector), | 57 exit_collector_(exit_collector), |
| 58 last_used_block_id_(0), // 0 is used for the graph entry. | 58 last_used_block_id_(0), // 0 is used for the graph entry. |
| 59 context_level_(0), | 59 context_level_(0), |
| 60 last_used_try_index_(CatchClauseNode::kInvalidTryIndex), | 60 last_used_try_index_(CatchClauseNode::kInvalidTryIndex), |
| 61 try_index_(CatchClauseNode::kInvalidTryIndex), | 61 try_index_(CatchClauseNode::kInvalidTryIndex), |
| 62 loop_depth_(0), |
| 62 graph_entry_(NULL), | 63 graph_entry_(NULL), |
| 63 args_pushed_(0), | 64 args_pushed_(0), |
| 64 osr_id_(osr_id) { } | 65 osr_id_(osr_id) { } |
| 65 | 66 |
| 66 | 67 |
| 67 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) { | 68 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) { |
| 68 graph_entry_->AddCatchEntry(entry); | 69 graph_entry_->AddCatchEntry(entry); |
| 69 } | 70 } |
| 70 | 71 |
| 71 | 72 |
| (...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 492 Instruction* body_exit = AppendFragment(body_entry, body_fragment); | 493 Instruction* body_exit = AppendFragment(body_entry, body_fragment); |
| 493 | 494 |
| 494 // 2. Connect the test to this graph, including the body if reachable and | 495 // 2. Connect the test to this graph, including the body if reachable and |
| 495 // using a fresh join node if the body is reachable and has an open exit. | 496 // using a fresh join node if the body is reachable and has an open exit. |
| 496 if (body_exit == NULL) { | 497 if (body_exit == NULL) { |
| 497 Append(test_fragment); | 498 Append(test_fragment); |
| 498 } else { | 499 } else { |
| 499 JoinEntryInstr* join = | 500 JoinEntryInstr* join = |
| 500 new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); | 501 new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); |
| 501 CheckStackOverflowInstr* check = | 502 CheckStackOverflowInstr* check = |
| 502 new CheckStackOverflowInstr(token_pos, true); | 503 new CheckStackOverflowInstr(token_pos, owner()->loop_depth()); |
| 503 join->LinkTo(check); | 504 join->LinkTo(check); |
| 504 check->LinkTo(test_fragment.entry()); | 505 check->LinkTo(test_fragment.entry()); |
| 505 Goto(join); | 506 Goto(join); |
| 506 body_exit->Goto(join); | 507 body_exit->Goto(join); |
| 507 } | 508 } |
| 508 | 509 |
| 509 // 3. Set the exit to the graph to be the false successor of the test, a | 510 // 3. Set the exit to the graph to be the false successor of the test, a |
| 510 // fresh target node | 511 // fresh target node |
| 511 exit_ = test_fragment.CreateFalseSuccessor(); | 512 exit_ = test_fragment.CreateFalseSuccessor(); |
| 512 } | 513 } |
| (...skipping 1081 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1594 // body: <Sequence> } | 1595 // body: <Sequence> } |
| 1595 // The fragment is composed as follows: | 1596 // The fragment is composed as follows: |
| 1596 // a) loop-join | 1597 // a) loop-join |
| 1597 // b) [ test ] -> (body-entry-target, loop-exit-target) | 1598 // b) [ test ] -> (body-entry-target, loop-exit-target) |
| 1598 // c) body-entry-target | 1599 // c) body-entry-target |
| 1599 // d) [ body ] -> (continue-join) | 1600 // d) [ body ] -> (continue-join) |
| 1600 // e) continue-join -> (loop-join) | 1601 // e) continue-join -> (loop-join) |
| 1601 // f) loop-exit-target | 1602 // f) loop-exit-target |
| 1602 // g) break-join (optional) | 1603 // g) break-join (optional) |
| 1603 void EffectGraphVisitor::VisitWhileNode(WhileNode* node) { | 1604 void EffectGraphVisitor::VisitWhileNode(WhileNode* node) { |
| 1605 owner()->IncrementLoopDepth(); |
| 1604 TestGraphVisitor for_test(owner(), | 1606 TestGraphVisitor for_test(owner(), |
| 1605 temp_index(), | 1607 temp_index(), |
| 1606 node->condition()->token_pos()); | 1608 node->condition()->token_pos()); |
| 1607 node->condition()->Visit(&for_test); | 1609 node->condition()->Visit(&for_test); |
| 1608 ASSERT(!for_test.is_empty()); // Language spec. | 1610 ASSERT(!for_test.is_empty()); // Language spec. |
| 1609 | 1611 |
| 1610 EffectGraphVisitor for_body(owner(), temp_index()); | 1612 EffectGraphVisitor for_body(owner(), temp_index()); |
| 1611 node->body()->Visit(&for_body); | 1613 node->body()->Visit(&for_body); |
| 1612 | 1614 |
| 1613 // Labels are set after body traversal. | 1615 // Labels are set after body traversal. |
| 1614 SourceLabel* lbl = node->label(); | 1616 SourceLabel* lbl = node->label(); |
| 1615 ASSERT(lbl != NULL); | 1617 ASSERT(lbl != NULL); |
| 1616 JoinEntryInstr* join = lbl->join_for_continue(); | 1618 JoinEntryInstr* join = lbl->join_for_continue(); |
| 1617 if (join != NULL) { | 1619 if (join != NULL) { |
| 1618 if (for_body.is_open()) for_body.Goto(join); | 1620 if (for_body.is_open()) for_body.Goto(join); |
| 1619 for_body.exit_ = join; | 1621 for_body.exit_ = join; |
| 1620 } | 1622 } |
| 1621 TieLoop(node->token_pos(), for_test, for_body); | 1623 TieLoop(node->token_pos(), for_test, for_body); |
| 1622 join = lbl->join_for_break(); | 1624 join = lbl->join_for_break(); |
| 1623 if (join != NULL) { | 1625 if (join != NULL) { |
| 1624 Goto(join); | 1626 Goto(join); |
| 1625 exit_ = join; | 1627 exit_ = join; |
| 1626 } | 1628 } |
| 1629 owner()->DecrementLoopDepth(); |
| 1627 } | 1630 } |
| 1628 | 1631 |
| 1629 | 1632 |
| 1630 // The fragment is composed as follows: | 1633 // The fragment is composed as follows: |
| 1631 // a) body-entry-join | 1634 // a) body-entry-join |
| 1632 // b) [ body ] | 1635 // b) [ body ] |
| 1633 // c) test-entry (continue-join or body-exit-target) | 1636 // c) test-entry (continue-join or body-exit-target) |
| 1634 // d) [ test-entry ] -> (back-target, loop-exit-target) | 1637 // d) [ test-entry ] -> (back-target, loop-exit-target) |
| 1635 // e) back-target -> (body-entry-join) | 1638 // e) back-target -> (body-entry-join) |
| 1636 // f) loop-exit-target | 1639 // f) loop-exit-target |
| 1637 // g) break-join | 1640 // g) break-join |
| 1638 void EffectGraphVisitor::VisitDoWhileNode(DoWhileNode* node) { | 1641 void EffectGraphVisitor::VisitDoWhileNode(DoWhileNode* node) { |
| 1642 owner()->IncrementLoopDepth(); |
| 1639 // Traverse body first in order to generate continue and break labels. | 1643 // Traverse body first in order to generate continue and break labels. |
| 1640 EffectGraphVisitor for_body(owner(), temp_index()); | 1644 EffectGraphVisitor for_body(owner(), temp_index()); |
| 1641 node->body()->Visit(&for_body); | 1645 node->body()->Visit(&for_body); |
| 1642 | 1646 |
| 1643 TestGraphVisitor for_test(owner(), | 1647 TestGraphVisitor for_test(owner(), |
| 1644 temp_index(), | 1648 temp_index(), |
| 1645 node->condition()->token_pos()); | 1649 node->condition()->token_pos()); |
| 1646 node->condition()->Visit(&for_test); | 1650 node->condition()->Visit(&for_test); |
| 1647 ASSERT(is_open()); | 1651 ASSERT(is_open()); |
| 1648 | 1652 |
| 1649 // Tie do-while loop (test is after the body). | 1653 // Tie do-while loop (test is after the body). |
| 1650 JoinEntryInstr* body_entry_join = | 1654 JoinEntryInstr* body_entry_join = |
| 1651 new JoinEntryInstr(owner()->AllocateBlockId(), | 1655 new JoinEntryInstr(owner()->AllocateBlockId(), |
| 1652 owner()->try_index()); | 1656 owner()->try_index()); |
| 1653 Goto(body_entry_join); | 1657 Goto(body_entry_join); |
| 1654 Instruction* body_exit = AppendFragment(body_entry_join, for_body); | 1658 Instruction* body_exit = AppendFragment(body_entry_join, for_body); |
| 1655 | 1659 |
| 1656 JoinEntryInstr* join = node->label()->join_for_continue(); | 1660 JoinEntryInstr* join = node->label()->join_for_continue(); |
| 1657 if ((body_exit != NULL) || (join != NULL)) { | 1661 if ((body_exit != NULL) || (join != NULL)) { |
| 1658 if (join == NULL) { | 1662 if (join == NULL) { |
| 1659 join = new JoinEntryInstr(owner()->AllocateBlockId(), | 1663 join = new JoinEntryInstr(owner()->AllocateBlockId(), |
| 1660 owner()->try_index()); | 1664 owner()->try_index()); |
| 1661 } | 1665 } |
| 1662 CheckStackOverflowInstr* check = | 1666 CheckStackOverflowInstr* check = |
| 1663 new CheckStackOverflowInstr(node->token_pos(), true); | 1667 new CheckStackOverflowInstr(node->token_pos(), owner()->loop_depth()); |
| 1664 join->LinkTo(check); | 1668 join->LinkTo(check); |
| 1665 check->LinkTo(for_test.entry()); | 1669 check->LinkTo(for_test.entry()); |
| 1666 if (body_exit != NULL) { | 1670 if (body_exit != NULL) { |
| 1667 body_exit->Goto(join); | 1671 body_exit->Goto(join); |
| 1668 } | 1672 } |
| 1669 } | 1673 } |
| 1670 | 1674 |
| 1671 for_test.IfTrueGoto(body_entry_join); | 1675 for_test.IfTrueGoto(body_entry_join); |
| 1672 join = node->label()->join_for_break(); | 1676 join = node->label()->join_for_break(); |
| 1673 if (join == NULL) { | 1677 if (join == NULL) { |
| 1674 exit_ = for_test.CreateFalseSuccessor(); | 1678 exit_ = for_test.CreateFalseSuccessor(); |
| 1675 } else { | 1679 } else { |
| 1676 for_test.IfFalseGoto(join); | 1680 for_test.IfFalseGoto(join); |
| 1677 exit_ = join; | 1681 exit_ = join; |
| 1678 } | 1682 } |
| 1683 owner()->DecrementLoopDepth(); |
| 1679 } | 1684 } |
| 1680 | 1685 |
| 1681 | 1686 |
| 1682 // A ForNode can contain break and continue jumps. 'break' joins to | 1687 // A ForNode can contain break and continue jumps. 'break' joins to |
| 1683 // ForNode exit, 'continue' joins at increment entry. The fragment is composed | 1688 // ForNode exit, 'continue' joins at increment entry. The fragment is composed |
| 1684 // as follows: | 1689 // as follows: |
| 1685 // a) [ initializer ] | 1690 // a) [ initializer ] |
| 1686 // b) loop-join | 1691 // b) loop-join |
| 1687 // c) [ test ] -> (body-entry-target, loop-exit-target) | 1692 // c) [ test ] -> (body-entry-target, loop-exit-target) |
| 1688 // d) body-entry-target | 1693 // d) body-entry-target |
| 1689 // e) [ body ] | 1694 // e) [ body ] |
| 1690 // f) continue-join (optional) | 1695 // f) continue-join (optional) |
| 1691 // g) [ increment ] -> (loop-join) | 1696 // g) [ increment ] -> (loop-join) |
| 1692 // h) loop-exit-target | 1697 // h) loop-exit-target |
| 1693 // i) break-join | 1698 // i) break-join |
| 1694 void EffectGraphVisitor::VisitForNode(ForNode* node) { | 1699 void EffectGraphVisitor::VisitForNode(ForNode* node) { |
| 1695 EffectGraphVisitor for_initializer(owner(), temp_index()); | 1700 EffectGraphVisitor for_initializer(owner(), temp_index()); |
| 1696 node->initializer()->Visit(&for_initializer); | 1701 node->initializer()->Visit(&for_initializer); |
| 1697 Append(for_initializer); | 1702 Append(for_initializer); |
| 1698 ASSERT(is_open()); | 1703 ASSERT(is_open()); |
| 1699 | 1704 |
| 1705 owner()->IncrementLoopDepth(); |
| 1700 // Compose body to set any jump labels. | 1706 // Compose body to set any jump labels. |
| 1701 EffectGraphVisitor for_body(owner(), temp_index()); | 1707 EffectGraphVisitor for_body(owner(), temp_index()); |
| 1702 node->body()->Visit(&for_body); | 1708 node->body()->Visit(&for_body); |
| 1703 | 1709 |
| 1704 EffectGraphVisitor for_increment(owner(), temp_index()); | 1710 EffectGraphVisitor for_increment(owner(), temp_index()); |
| 1705 node->increment()->Visit(&for_increment); | 1711 node->increment()->Visit(&for_increment); |
| 1706 | 1712 |
| 1707 // Join the loop body and increment and then tie the loop. | 1713 // Join the loop body and increment and then tie the loop. |
| 1708 JoinEntryInstr* join = node->label()->join_for_continue(); | 1714 JoinEntryInstr* join = node->label()->join_for_continue(); |
| 1709 if ((join != NULL) || for_body.is_open()) { | 1715 if ((join != NULL) || for_body.is_open()) { |
| 1710 JoinEntryInstr* loop_start = | 1716 JoinEntryInstr* loop_start = |
| 1711 new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); | 1717 new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); |
| 1712 if (join != NULL) { | 1718 if (join != NULL) { |
| 1713 if (for_body.is_open()) for_body.Goto(join); | 1719 if (for_body.is_open()) for_body.Goto(join); |
| 1714 AppendFragment(join, for_increment); | 1720 AppendFragment(join, for_increment); |
| 1715 for_increment.Goto(loop_start); | 1721 for_increment.Goto(loop_start); |
| 1716 } else { | 1722 } else { |
| 1717 for_body.Append(for_increment); | 1723 for_body.Append(for_increment); |
| 1718 for_body.Goto(loop_start); | 1724 for_body.Goto(loop_start); |
| 1719 } | 1725 } |
| 1720 Goto(loop_start); | 1726 Goto(loop_start); |
| 1721 exit_ = loop_start; | 1727 exit_ = loop_start; |
| 1722 AddInstruction(new CheckStackOverflowInstr(node->token_pos(), true)); | 1728 AddInstruction( |
| 1729 new CheckStackOverflowInstr(node->token_pos(), owner()->loop_depth())); |
| 1723 } | 1730 } |
| 1724 | 1731 |
| 1725 if (node->condition() == NULL) { | 1732 if (node->condition() == NULL) { |
| 1726 // Endless loop, no test. | 1733 // Endless loop, no test. |
| 1727 JoinEntryInstr* body_entry = | 1734 JoinEntryInstr* body_entry = |
| 1728 new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); | 1735 new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); |
| 1729 AppendFragment(body_entry, for_body); | 1736 AppendFragment(body_entry, for_body); |
| 1730 Goto(body_entry); | 1737 Goto(body_entry); |
| 1731 if (node->label()->join_for_break() != NULL) { | 1738 if (node->label()->join_for_break() != NULL) { |
| 1732 // Control flow of ForLoop continues into join_for_break. | 1739 // Control flow of ForLoop continues into join_for_break. |
| 1733 exit_ = node->label()->join_for_break(); | 1740 exit_ = node->label()->join_for_break(); |
| 1734 } | 1741 } |
| 1735 } else { | 1742 } else { |
| 1736 TestGraphVisitor for_test(owner(), | 1743 TestGraphVisitor for_test(owner(), |
| 1737 temp_index(), | 1744 temp_index(), |
| 1738 node->condition()->token_pos()); | 1745 node->condition()->token_pos()); |
| 1739 node->condition()->Visit(&for_test); | 1746 node->condition()->Visit(&for_test); |
| 1740 Append(for_test); | 1747 Append(for_test); |
| 1741 | 1748 |
| 1742 BlockEntryInstr* body_entry = for_test.CreateTrueSuccessor(); | 1749 BlockEntryInstr* body_entry = for_test.CreateTrueSuccessor(); |
| 1743 AppendFragment(body_entry, for_body); | 1750 AppendFragment(body_entry, for_body); |
| 1744 | 1751 |
| 1745 if (node->label()->join_for_break() == NULL) { | 1752 if (node->label()->join_for_break() == NULL) { |
| 1746 exit_ = for_test.CreateFalseSuccessor(); | 1753 exit_ = for_test.CreateFalseSuccessor(); |
| 1747 } else { | 1754 } else { |
| 1748 for_test.IfFalseGoto(node->label()->join_for_break()); | 1755 for_test.IfFalseGoto(node->label()->join_for_break()); |
| 1749 exit_ = node->label()->join_for_break(); | 1756 exit_ = node->label()->join_for_break(); |
| 1750 } | 1757 } |
| 1751 } | 1758 } |
| 1759 owner()->DecrementLoopDepth(); |
| 1752 } | 1760 } |
| 1753 | 1761 |
| 1754 | 1762 |
| 1755 void EffectGraphVisitor::VisitJumpNode(JumpNode* node) { | 1763 void EffectGraphVisitor::VisitJumpNode(JumpNode* node) { |
| 1756 for (intptr_t i = 0; i < node->inlined_finally_list_length(); i++) { | 1764 for (intptr_t i = 0; i < node->inlined_finally_list_length(); i++) { |
| 1757 EffectGraphVisitor for_effect(owner(), temp_index()); | 1765 EffectGraphVisitor for_effect(owner(), temp_index()); |
| 1758 node->InlinedFinallyNodeAt(i)->Visit(&for_effect); | 1766 node->InlinedFinallyNodeAt(i)->Visit(&for_effect); |
| 1759 Append(for_effect); | 1767 Append(for_effect); |
| 1760 if (!is_open()) return; | 1768 if (!is_open()) return; |
| 1761 } | 1769 } |
| (...skipping 1695 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3457 AstPrinter::PrintFunctionNodes(*parsed_function()); | 3465 AstPrinter::PrintFunctionNodes(*parsed_function()); |
| 3458 } | 3466 } |
| 3459 const Function& function = parsed_function()->function(); | 3467 const Function& function = parsed_function()->function(); |
| 3460 TargetEntryInstr* normal_entry = | 3468 TargetEntryInstr* normal_entry = |
| 3461 new TargetEntryInstr(AllocateBlockId(), | 3469 new TargetEntryInstr(AllocateBlockId(), |
| 3462 CatchClauseNode::kInvalidTryIndex); | 3470 CatchClauseNode::kInvalidTryIndex); |
| 3463 graph_entry_ = new GraphEntryInstr(*parsed_function(), normal_entry, osr_id_); | 3471 graph_entry_ = new GraphEntryInstr(*parsed_function(), normal_entry, osr_id_); |
| 3464 EffectGraphVisitor for_effect(this, 0); | 3472 EffectGraphVisitor for_effect(this, 0); |
| 3465 // This check may be deleted if the generated code is leaf. | 3473 // This check may be deleted if the generated code is leaf. |
| 3466 CheckStackOverflowInstr* check = | 3474 CheckStackOverflowInstr* check = |
| 3467 new CheckStackOverflowInstr(function.token_pos(), false); | 3475 new CheckStackOverflowInstr(function.token_pos(), 0); |
| 3468 // If we are inlining don't actually attach the stack check. We must still | 3476 // If we are inlining don't actually attach the stack check. We must still |
| 3469 // create the stack check in order to allocate a deopt id. | 3477 // create the stack check in order to allocate a deopt id. |
| 3470 if (!IsInlining()) for_effect.AddInstruction(check); | 3478 if (!IsInlining()) for_effect.AddInstruction(check); |
| 3471 parsed_function()->node_sequence()->Visit(&for_effect); | 3479 parsed_function()->node_sequence()->Visit(&for_effect); |
| 3472 AppendFragment(normal_entry, for_effect); | 3480 AppendFragment(normal_entry, for_effect); |
| 3473 // Check that the graph is properly terminated. | 3481 // Check that the graph is properly terminated. |
| 3474 ASSERT(!for_effect.is_open()); | 3482 ASSERT(!for_effect.is_open()); |
| 3475 | 3483 |
| 3476 // When compiling for OSR, use a depth first search to prune instructions | 3484 // When compiling for OSR, use a depth first search to prune instructions |
| 3477 // unreachable from the OSR entry. Catch entries are not (yet) properly | 3485 // unreachable from the OSR entry. Catch entries are not (yet) properly |
| (...skipping 25 matching lines...) Expand all Loading... |
| 3503 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | 3511 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
| 3504 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 3512 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
| 3505 OS::SNPrint(chars, len, kFormat, function_name, reason); | 3513 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 3506 const Error& error = Error::Handle( | 3514 const Error& error = Error::Handle( |
| 3507 LanguageError::New(String::Handle(String::New(chars)))); | 3515 LanguageError::New(String::Handle(String::New(chars)))); |
| 3508 Isolate::Current()->long_jump_base()->Jump(1, error); | 3516 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 3509 } | 3517 } |
| 3510 | 3518 |
| 3511 | 3519 |
| 3512 } // namespace dart | 3520 } // namespace dart |
| OLD | NEW |