OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/bytecode-graph-builder.h" | 5 #include "src/compiler/bytecode-graph-builder.h" |
6 | 6 |
7 #include "src/compiler/bytecode-branch-analysis.h" | 7 #include "src/compiler/bytecode-branch-analysis.h" |
8 #include "src/compiler/linkage.h" | 8 #include "src/compiler/linkage.h" |
9 #include "src/compiler/operator-properties.h" | 9 #include "src/compiler/operator-properties.h" |
10 #include "src/interpreter/bytecodes.h" | 10 #include "src/interpreter/bytecodes.h" |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 } | 55 } |
56 | 56 |
57 Node* Context() const { return context_; } | 57 Node* Context() const { return context_; } |
58 void SetContext(Node* new_context) { context_ = new_context; } | 58 void SetContext(Node* new_context) { context_ = new_context; } |
59 | 59 |
60 Environment* CopyForConditional() const; | 60 Environment* CopyForConditional() const; |
61 Environment* CopyForLoop(); | 61 Environment* CopyForLoop(); |
62 void Merge(Environment* other); | 62 void Merge(Environment* other); |
63 void PrepareForOsr(); | 63 void PrepareForOsr(); |
64 | 64 |
| 65 void PrepareForLoopExit(Node* loop); |
| 66 |
65 private: | 67 private: |
66 explicit Environment(const Environment* copy); | 68 explicit Environment(const Environment* copy); |
67 void PrepareForLoop(); | 69 void PrepareForLoop(); |
68 bool StateValuesAreUpToDate(Node** state_values, int offset, int count, | 70 bool StateValuesAreUpToDate(Node** state_values, int offset, int count, |
69 int output_poke_start, int output_poke_end); | 71 int output_poke_start, int output_poke_end); |
70 bool StateValuesRequireUpdate(Node** state_values, int offset, int count); | 72 bool StateValuesRequireUpdate(Node** state_values, int offset, int count); |
71 void UpdateStateValues(Node** state_values, int offset, int count); | 73 void UpdateStateValues(Node** state_values, int offset, int count); |
72 | 74 |
73 int RegisterToValuesIndex(interpreter::Register the_register) const; | 75 int RegisterToValuesIndex(interpreter::Register the_register) const; |
74 | 76 |
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 DCHECK_LE(static_cast<size_t>(offset + count), values()->size()); | 401 DCHECK_LE(static_cast<size_t>(offset + count), values()->size()); |
400 Node** env_values = (count == 0) ? nullptr : &values()->at(offset); | 402 Node** env_values = (count == 0) ? nullptr : &values()->at(offset); |
401 for (int i = 0; i < count; i++) { | 403 for (int i = 0; i < count; i++) { |
402 if ((*state_values)->InputAt(i) != env_values[i]) { | 404 if ((*state_values)->InputAt(i) != env_values[i]) { |
403 return true; | 405 return true; |
404 } | 406 } |
405 } | 407 } |
406 return false; | 408 return false; |
407 } | 409 } |
408 | 410 |
| 411 void BytecodeGraphBuilder::Environment::PrepareForLoopExit(Node* loop) { |
| 412 DCHECK_EQ(loop->opcode(), IrOpcode::kLoop); |
| 413 |
| 414 Node* control = GetControlDependency(); |
| 415 |
| 416 // Create the loop exit node. |
| 417 Node* loop_exit = graph()->NewNode(common()->LoopExit(), control, loop); |
| 418 UpdateControlDependency(loop_exit); |
| 419 |
| 420 // Rename the effect. |
| 421 Node* effect_rename = graph()->NewNode(common()->LoopExitEffect(), |
| 422 GetEffectDependency(), loop_exit); |
| 423 UpdateEffectDependency(effect_rename); |
| 424 |
| 425 // Rename the current context. |
| 426 context_ = graph()->NewNode(common()->LoopExitValue(), context_, loop_exit); |
| 427 |
| 428 // Rename the environmnent values. |
| 429 for (size_t i = 0; i < values_.size(); i++) { |
| 430 Node* rename = |
| 431 graph()->NewNode(common()->LoopExitValue(), values_[i], loop_exit); |
| 432 values_[i] = rename; |
| 433 } |
| 434 } |
409 | 435 |
410 void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values, | 436 void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values, |
411 int offset, | 437 int offset, |
412 int count) { | 438 int count) { |
413 if (StateValuesRequireUpdate(state_values, offset, count)) { | 439 if (StateValuesRequireUpdate(state_values, offset, count)) { |
414 const Operator* op = common()->StateValues(count); | 440 const Operator* op = common()->StateValues(count); |
415 (*state_values) = graph()->NewNode(op, count, &values()->at(offset)); | 441 (*state_values) = graph()->NewNode(op, count, &values()->at(offset)); |
416 } | 442 } |
417 } | 443 } |
418 | 444 |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
564 int const input_count = static_cast<int>(exit_controls_.size()); | 590 int const input_count = static_cast<int>(exit_controls_.size()); |
565 Node** const inputs = &exit_controls_.front(); | 591 Node** const inputs = &exit_controls_.front(); |
566 Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs); | 592 Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs); |
567 graph()->SetEnd(end); | 593 graph()->SetEnd(end); |
568 | 594 |
569 return true; | 595 return true; |
570 } | 596 } |
571 | 597 |
572 void BytecodeGraphBuilder::VisitBytecodes() { | 598 void BytecodeGraphBuilder::VisitBytecodes() { |
573 BytecodeBranchAnalysis analysis(bytecode_array(), local_zone()); | 599 BytecodeBranchAnalysis analysis(bytecode_array(), local_zone()); |
| 600 BytecodeLoopAnalysis loop_analysis(bytecode_array(), &analysis, local_zone()); |
574 analysis.Analyze(); | 601 analysis.Analyze(); |
| 602 loop_analysis.Analyze(); |
575 set_branch_analysis(&analysis); | 603 set_branch_analysis(&analysis); |
| 604 set_loop_analysis(&loop_analysis); |
576 interpreter::BytecodeArrayIterator iterator(bytecode_array()); | 605 interpreter::BytecodeArrayIterator iterator(bytecode_array()); |
577 set_bytecode_iterator(&iterator); | 606 set_bytecode_iterator(&iterator); |
578 while (!iterator.done()) { | 607 while (!iterator.done()) { |
579 int current_offset = iterator.current_offset(); | 608 int current_offset = iterator.current_offset(); |
580 EnterAndExitExceptionHandlers(current_offset); | 609 EnterAndExitExceptionHandlers(current_offset); |
581 SwitchToMergeEnvironment(current_offset); | 610 SwitchToMergeEnvironment(current_offset); |
582 if (environment() != nullptr) { | 611 if (environment() != nullptr) { |
583 BuildLoopHeaderEnvironment(current_offset); | 612 BuildLoopHeaderEnvironment(current_offset); |
584 | 613 |
585 switch (iterator.current_bytecode()) { | 614 switch (iterator.current_bytecode()) { |
(...skipping 522 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1108 } | 1137 } |
1109 | 1138 |
1110 void BytecodeGraphBuilder::BuildThrow() { | 1139 void BytecodeGraphBuilder::BuildThrow() { |
1111 FrameStateBeforeAndAfter states(this); | 1140 FrameStateBeforeAndAfter states(this); |
1112 Node* value = environment()->LookupAccumulator(); | 1141 Node* value = environment()->LookupAccumulator(); |
1113 Node* call = NewNode(javascript()->CallRuntime(Runtime::kThrow), value); | 1142 Node* call = NewNode(javascript()->CallRuntime(Runtime::kThrow), value); |
1114 environment()->BindAccumulator(call, &states); | 1143 environment()->BindAccumulator(call, &states); |
1115 } | 1144 } |
1116 | 1145 |
1117 void BytecodeGraphBuilder::VisitThrow() { | 1146 void BytecodeGraphBuilder::VisitThrow() { |
| 1147 BuildLoopExitsForFunctionExit(); |
1118 BuildThrow(); | 1148 BuildThrow(); |
1119 Node* call = environment()->LookupAccumulator(); | 1149 Node* call = environment()->LookupAccumulator(); |
1120 Node* control = NewNode(common()->Throw(), call); | 1150 Node* control = NewNode(common()->Throw(), call); |
1121 MergeControlToLeaveFunction(control); | 1151 MergeControlToLeaveFunction(control); |
1122 } | 1152 } |
1123 | 1153 |
1124 void BytecodeGraphBuilder::VisitReThrow() { | 1154 void BytecodeGraphBuilder::VisitReThrow() { |
| 1155 BuildLoopExitsForFunctionExit(); |
1125 Node* value = environment()->LookupAccumulator(); | 1156 Node* value = environment()->LookupAccumulator(); |
1126 Node* call = NewNode(javascript()->CallRuntime(Runtime::kReThrow), value); | 1157 Node* call = NewNode(javascript()->CallRuntime(Runtime::kReThrow), value); |
1127 Node* control = NewNode(common()->Throw(), call); | 1158 Node* control = NewNode(common()->Throw(), call); |
1128 MergeControlToLeaveFunction(control); | 1159 MergeControlToLeaveFunction(control); |
1129 } | 1160 } |
1130 | 1161 |
1131 void BytecodeGraphBuilder::BuildBinaryOp(const Operator* js_op) { | 1162 void BytecodeGraphBuilder::BuildBinaryOp(const Operator* js_op) { |
1132 FrameStateBeforeAndAfter states(this); | 1163 FrameStateBeforeAndAfter states(this); |
1133 Node* left = | 1164 Node* left = |
1134 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); | 1165 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1431 void BytecodeGraphBuilder::VisitOsrPoll() { | 1462 void BytecodeGraphBuilder::VisitOsrPoll() { |
1432 // TODO(4764): This should be moved into the {VisitBytecodes} once we merge | 1463 // TODO(4764): This should be moved into the {VisitBytecodes} once we merge |
1433 // the polling with existing bytecode. This will also guarantee that we are | 1464 // the polling with existing bytecode. This will also guarantee that we are |
1434 // not missing the OSR entry point, which we wouldn't catch right now. | 1465 // not missing the OSR entry point, which we wouldn't catch right now. |
1435 if (osr_ast_id_.ToInt() == bytecode_iterator().current_offset()) { | 1466 if (osr_ast_id_.ToInt() == bytecode_iterator().current_offset()) { |
1436 environment()->PrepareForOsr(); | 1467 environment()->PrepareForOsr(); |
1437 } | 1468 } |
1438 } | 1469 } |
1439 | 1470 |
1440 void BytecodeGraphBuilder::VisitReturn() { | 1471 void BytecodeGraphBuilder::VisitReturn() { |
| 1472 BuildLoopExitsForFunctionExit(); |
1441 Node* control = | 1473 Node* control = |
1442 NewNode(common()->Return(), environment()->LookupAccumulator()); | 1474 NewNode(common()->Return(), environment()->LookupAccumulator()); |
1443 MergeControlToLeaveFunction(control); | 1475 MergeControlToLeaveFunction(control); |
1444 } | 1476 } |
1445 | 1477 |
1446 void BytecodeGraphBuilder::VisitDebugger() { | 1478 void BytecodeGraphBuilder::VisitDebugger() { |
1447 FrameStateBeforeAndAfter states(this); | 1479 FrameStateBeforeAndAfter states(this); |
1448 Node* call = | 1480 Node* call = |
1449 NewNode(javascript()->CallRuntime(Runtime::kHandleDebuggerStatement)); | 1481 NewNode(javascript()->CallRuntime(Runtime::kHandleDebuggerStatement)); |
1450 environment()->BindAccumulator(call, &states); | 1482 environment()->BindAccumulator(call, &states); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1576 | 1608 |
1577 void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) { | 1609 void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) { |
1578 if (branch_analysis()->backward_branches_target(current_offset)) { | 1610 if (branch_analysis()->backward_branches_target(current_offset)) { |
1579 // Add loop header and store a copy so we can connect merged back | 1611 // Add loop header and store a copy so we can connect merged back |
1580 // edge inputs to the loop header. | 1612 // edge inputs to the loop header. |
1581 merge_environments_[current_offset] = environment()->CopyForLoop(); | 1613 merge_environments_[current_offset] = environment()->CopyForLoop(); |
1582 } | 1614 } |
1583 } | 1615 } |
1584 | 1616 |
1585 void BytecodeGraphBuilder::MergeIntoSuccessorEnvironment(int target_offset) { | 1617 void BytecodeGraphBuilder::MergeIntoSuccessorEnvironment(int target_offset) { |
| 1618 BuildLoopExitsForBranch(target_offset); |
1586 if (merge_environments_[target_offset] == nullptr) { | 1619 if (merge_environments_[target_offset] == nullptr) { |
1587 // Append merge nodes to the environment. We may merge here with another | 1620 // Append merge nodes to the environment. We may merge here with another |
1588 // environment. So add a place holder for merge nodes. We may add redundant | 1621 // environment. So add a place holder for merge nodes. We may add redundant |
1589 // but will be eliminated in a later pass. | 1622 // but will be eliminated in a later pass. |
1590 // TODO(mstarzinger): Be smarter about this! | 1623 // TODO(mstarzinger): Be smarter about this! |
1591 NewMerge(); | 1624 NewMerge(); |
1592 merge_environments_[target_offset] = environment(); | 1625 merge_environments_[target_offset] = environment(); |
1593 } else { | 1626 } else { |
1594 merge_environments_[target_offset]->Merge(environment()); | 1627 merge_environments_[target_offset]->Merge(environment()); |
1595 } | 1628 } |
1596 set_environment(nullptr); | 1629 set_environment(nullptr); |
1597 } | 1630 } |
1598 | 1631 |
1599 void BytecodeGraphBuilder::MergeControlToLeaveFunction(Node* exit) { | 1632 void BytecodeGraphBuilder::MergeControlToLeaveFunction(Node* exit) { |
1600 exit_controls_.push_back(exit); | 1633 exit_controls_.push_back(exit); |
1601 set_environment(nullptr); | 1634 set_environment(nullptr); |
1602 } | 1635 } |
1603 | 1636 |
| 1637 void BytecodeGraphBuilder::BuildLoopExitsForBranch(int target_offset) { |
| 1638 int origin_offset = bytecode_iterator().current_offset(); |
| 1639 // Only build loop exits for forward edges. |
| 1640 if (target_offset > origin_offset) { |
| 1641 BuildLoopExitsUntilLoop(loop_analysis()->GetLoopOffsetFor(target_offset)); |
| 1642 } |
| 1643 } |
| 1644 |
| 1645 void BytecodeGraphBuilder::BuildLoopExitsUntilLoop(int loop_offset) { |
| 1646 int origin_offset = bytecode_iterator().current_offset(); |
| 1647 int current_loop = loop_analysis()->GetLoopOffsetFor(origin_offset); |
| 1648 while (loop_offset < current_loop) { |
| 1649 Node* loop_node = merge_environments_[current_loop]->GetControlDependency(); |
| 1650 environment()->PrepareForLoopExit(loop_node); |
| 1651 current_loop = loop_analysis()->GetParentLoopFor(current_loop); |
| 1652 } |
| 1653 } |
| 1654 |
| 1655 void BytecodeGraphBuilder::BuildLoopExitsForFunctionExit() { |
| 1656 BuildLoopExitsUntilLoop(-1); |
| 1657 } |
| 1658 |
1604 void BytecodeGraphBuilder::BuildJump() { | 1659 void BytecodeGraphBuilder::BuildJump() { |
1605 MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); | 1660 MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); |
1606 } | 1661 } |
1607 | 1662 |
1608 | 1663 |
1609 void BytecodeGraphBuilder::BuildConditionalJump(Node* condition) { | 1664 void BytecodeGraphBuilder::BuildConditionalJump(Node* condition) { |
1610 NewBranch(condition); | 1665 NewBranch(condition); |
1611 Environment* if_false_environment = environment()->CopyForConditional(); | 1666 Environment* if_false_environment = environment()->CopyForConditional(); |
1612 NewIfTrue(); | 1667 NewIfTrue(); |
1613 MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); | 1668 MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1832 // Phi does not exist yet, introduce one. | 1887 // Phi does not exist yet, introduce one. |
1833 value = NewPhi(inputs, value, control); | 1888 value = NewPhi(inputs, value, control); |
1834 value->ReplaceInput(inputs - 1, other); | 1889 value->ReplaceInput(inputs - 1, other); |
1835 } | 1890 } |
1836 return value; | 1891 return value; |
1837 } | 1892 } |
1838 | 1893 |
1839 } // namespace compiler | 1894 } // namespace compiler |
1840 } // namespace internal | 1895 } // namespace internal |
1841 } // namespace v8 | 1896 } // namespace v8 |
OLD | NEW |