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 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 DCHECK_LE(static_cast<size_t>(offset + count), values()->size()); | 392 DCHECK_LE(static_cast<size_t>(offset + count), values()->size()); |
391 Node** env_values = (count == 0) ? nullptr : &values()->at(offset); | 393 Node** env_values = (count == 0) ? nullptr : &values()->at(offset); |
392 for (int i = 0; i < count; i++) { | 394 for (int i = 0; i < count; i++) { |
393 if ((*state_values)->InputAt(i) != env_values[i]) { | 395 if ((*state_values)->InputAt(i) != env_values[i]) { |
394 return true; | 396 return true; |
395 } | 397 } |
396 } | 398 } |
397 return false; | 399 return false; |
398 } | 400 } |
399 | 401 |
| 402 void BytecodeGraphBuilder::Environment::PrepareForLoopExit(Node* loop) { |
| 403 DCHECK_EQ(loop->opcode(), IrOpcode::kLoop); |
| 404 |
| 405 Node* control = GetControlDependency(); |
| 406 |
| 407 // Create the loop exit node. |
| 408 Node* loop_exit = graph()->NewNode(common()->LoopExit(), control, loop); |
| 409 UpdateControlDependency(loop_exit); |
| 410 |
| 411 // Rename the effect. |
| 412 Node* effect_rename = graph()->NewNode(common()->LoopExitEffect(), |
| 413 GetEffectDependency(), loop_exit); |
| 414 UpdateEffectDependency(effect_rename); |
| 415 |
| 416 // Rename the current context. |
| 417 context_ = graph()->NewNode(common()->LoopExitValue(), context_, loop_exit); |
| 418 |
| 419 // Rename the environmnent values. |
| 420 for (size_t i = 0; i < values_.size(); i++) { |
| 421 Node* rename = |
| 422 graph()->NewNode(common()->LoopExitValue(), values_[i], loop_exit); |
| 423 values_[i] = rename; |
| 424 } |
| 425 } |
400 | 426 |
401 void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values, | 427 void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values, |
402 int offset, | 428 int offset, |
403 int count) { | 429 int count) { |
404 if (StateValuesRequireUpdate(state_values, offset, count)) { | 430 if (StateValuesRequireUpdate(state_values, offset, count)) { |
405 const Operator* op = common()->StateValues(count); | 431 const Operator* op = common()->StateValues(count); |
406 (*state_values) = graph()->NewNode(op, count, &values()->at(offset)); | 432 (*state_values) = graph()->NewNode(op, count, &values()->at(offset)); |
407 } | 433 } |
408 } | 434 } |
409 | 435 |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
555 int const input_count = static_cast<int>(exit_controls_.size()); | 581 int const input_count = static_cast<int>(exit_controls_.size()); |
556 Node** const inputs = &exit_controls_.front(); | 582 Node** const inputs = &exit_controls_.front(); |
557 Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs); | 583 Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs); |
558 graph()->SetEnd(end); | 584 graph()->SetEnd(end); |
559 | 585 |
560 return true; | 586 return true; |
561 } | 587 } |
562 | 588 |
563 void BytecodeGraphBuilder::VisitBytecodes() { | 589 void BytecodeGraphBuilder::VisitBytecodes() { |
564 BytecodeBranchAnalysis analysis(bytecode_array(), local_zone()); | 590 BytecodeBranchAnalysis analysis(bytecode_array(), local_zone()); |
| 591 BytecodeLoopAnalysis loop_analysis(bytecode_array(), &analysis, local_zone()); |
565 analysis.Analyze(); | 592 analysis.Analyze(); |
| 593 loop_analysis.Analyze(); |
566 set_branch_analysis(&analysis); | 594 set_branch_analysis(&analysis); |
| 595 set_loop_analysis(&loop_analysis); |
567 interpreter::BytecodeArrayIterator iterator(bytecode_array()); | 596 interpreter::BytecodeArrayIterator iterator(bytecode_array()); |
568 set_bytecode_iterator(&iterator); | 597 set_bytecode_iterator(&iterator); |
569 while (!iterator.done()) { | 598 while (!iterator.done()) { |
570 int current_offset = iterator.current_offset(); | 599 int current_offset = iterator.current_offset(); |
571 EnterAndExitExceptionHandlers(current_offset); | 600 EnterAndExitExceptionHandlers(current_offset); |
572 SwitchToMergeEnvironment(current_offset); | 601 SwitchToMergeEnvironment(current_offset); |
573 if (environment() != nullptr) { | 602 if (environment() != nullptr) { |
574 BuildLoopHeaderEnvironment(current_offset); | 603 BuildLoopHeaderEnvironment(current_offset); |
575 | 604 |
576 switch (iterator.current_bytecode()) { | 605 switch (iterator.current_bytecode()) { |
(...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1106 } | 1135 } |
1107 | 1136 |
1108 void BytecodeGraphBuilder::BuildThrow() { | 1137 void BytecodeGraphBuilder::BuildThrow() { |
1109 FrameStateBeforeAndAfter states(this); | 1138 FrameStateBeforeAndAfter states(this); |
1110 Node* value = environment()->LookupAccumulator(); | 1139 Node* value = environment()->LookupAccumulator(); |
1111 Node* call = NewNode(javascript()->CallRuntime(Runtime::kThrow), value); | 1140 Node* call = NewNode(javascript()->CallRuntime(Runtime::kThrow), value); |
1112 environment()->BindAccumulator(call, &states); | 1141 environment()->BindAccumulator(call, &states); |
1113 } | 1142 } |
1114 | 1143 |
1115 void BytecodeGraphBuilder::VisitThrow() { | 1144 void BytecodeGraphBuilder::VisitThrow() { |
| 1145 BuildLoopExitsForFunctionExit(); |
1116 BuildThrow(); | 1146 BuildThrow(); |
1117 Node* call = environment()->LookupAccumulator(); | 1147 Node* call = environment()->LookupAccumulator(); |
1118 Node* control = NewNode(common()->Throw(), call); | 1148 Node* control = NewNode(common()->Throw(), call); |
1119 MergeControlToLeaveFunction(control); | 1149 MergeControlToLeaveFunction(control); |
1120 } | 1150 } |
1121 | 1151 |
1122 void BytecodeGraphBuilder::VisitReThrow() { | 1152 void BytecodeGraphBuilder::VisitReThrow() { |
| 1153 BuildLoopExitsForFunctionExit(); |
1123 Node* value = environment()->LookupAccumulator(); | 1154 Node* value = environment()->LookupAccumulator(); |
1124 Node* call = NewNode(javascript()->CallRuntime(Runtime::kReThrow), value); | 1155 Node* call = NewNode(javascript()->CallRuntime(Runtime::kReThrow), value); |
1125 Node* control = NewNode(common()->Throw(), call); | 1156 Node* control = NewNode(common()->Throw(), call); |
1126 MergeControlToLeaveFunction(control); | 1157 MergeControlToLeaveFunction(control); |
1127 } | 1158 } |
1128 | 1159 |
1129 void BytecodeGraphBuilder::BuildBinaryOp(const Operator* js_op) { | 1160 void BytecodeGraphBuilder::BuildBinaryOp(const Operator* js_op) { |
1130 FrameStateBeforeAndAfter states(this); | 1161 FrameStateBeforeAndAfter states(this); |
1131 Node* left = | 1162 Node* left = |
1132 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); | 1163 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); |
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1425 void BytecodeGraphBuilder::VisitOsrPoll() { | 1456 void BytecodeGraphBuilder::VisitOsrPoll() { |
1426 // TODO(4764): This should be moved into the {VisitBytecodes} once we merge | 1457 // TODO(4764): This should be moved into the {VisitBytecodes} once we merge |
1427 // the polling with existing bytecode. This will also guarantee that we are | 1458 // the polling with existing bytecode. This will also guarantee that we are |
1428 // not missing the OSR entry point, which we wouldn't catch right now. | 1459 // not missing the OSR entry point, which we wouldn't catch right now. |
1429 if (osr_ast_id_.ToInt() == bytecode_iterator().current_offset()) { | 1460 if (osr_ast_id_.ToInt() == bytecode_iterator().current_offset()) { |
1430 environment()->PrepareForOsr(); | 1461 environment()->PrepareForOsr(); |
1431 } | 1462 } |
1432 } | 1463 } |
1433 | 1464 |
1434 void BytecodeGraphBuilder::VisitReturn() { | 1465 void BytecodeGraphBuilder::VisitReturn() { |
| 1466 BuildLoopExitsForFunctionExit(); |
1435 Node* control = | 1467 Node* control = |
1436 NewNode(common()->Return(), environment()->LookupAccumulator()); | 1468 NewNode(common()->Return(), environment()->LookupAccumulator()); |
1437 MergeControlToLeaveFunction(control); | 1469 MergeControlToLeaveFunction(control); |
1438 } | 1470 } |
1439 | 1471 |
1440 void BytecodeGraphBuilder::VisitDebugger() { | 1472 void BytecodeGraphBuilder::VisitDebugger() { |
1441 FrameStateBeforeAndAfter states(this); | 1473 FrameStateBeforeAndAfter states(this); |
1442 Node* call = | 1474 Node* call = |
1443 NewNode(javascript()->CallRuntime(Runtime::kHandleDebuggerStatement)); | 1475 NewNode(javascript()->CallRuntime(Runtime::kHandleDebuggerStatement)); |
1444 environment()->BindAccumulator(call, &states); | 1476 environment()->BindAccumulator(call, &states); |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1571 | 1603 |
1572 void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) { | 1604 void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) { |
1573 if (branch_analysis()->backward_branches_target(current_offset)) { | 1605 if (branch_analysis()->backward_branches_target(current_offset)) { |
1574 // Add loop header and store a copy so we can connect merged back | 1606 // Add loop header and store a copy so we can connect merged back |
1575 // edge inputs to the loop header. | 1607 // edge inputs to the loop header. |
1576 merge_environments_[current_offset] = environment()->CopyForLoop(); | 1608 merge_environments_[current_offset] = environment()->CopyForLoop(); |
1577 } | 1609 } |
1578 } | 1610 } |
1579 | 1611 |
1580 void BytecodeGraphBuilder::MergeIntoSuccessorEnvironment(int target_offset) { | 1612 void BytecodeGraphBuilder::MergeIntoSuccessorEnvironment(int target_offset) { |
| 1613 BuildLoopExitsForBranch(target_offset); |
1581 if (merge_environments_[target_offset] == nullptr) { | 1614 if (merge_environments_[target_offset] == nullptr) { |
1582 // Append merge nodes to the environment. We may merge here with another | 1615 // Append merge nodes to the environment. We may merge here with another |
1583 // environment. So add a place holder for merge nodes. We may add redundant | 1616 // environment. So add a place holder for merge nodes. We may add redundant |
1584 // but will be eliminated in a later pass. | 1617 // but will be eliminated in a later pass. |
1585 // TODO(mstarzinger): Be smarter about this! | 1618 // TODO(mstarzinger): Be smarter about this! |
1586 NewMerge(); | 1619 NewMerge(); |
1587 merge_environments_[target_offset] = environment(); | 1620 merge_environments_[target_offset] = environment(); |
1588 } else { | 1621 } else { |
1589 merge_environments_[target_offset]->Merge(environment()); | 1622 merge_environments_[target_offset]->Merge(environment()); |
1590 } | 1623 } |
1591 set_environment(nullptr); | 1624 set_environment(nullptr); |
1592 } | 1625 } |
1593 | 1626 |
1594 void BytecodeGraphBuilder::MergeControlToLeaveFunction(Node* exit) { | 1627 void BytecodeGraphBuilder::MergeControlToLeaveFunction(Node* exit) { |
1595 exit_controls_.push_back(exit); | 1628 exit_controls_.push_back(exit); |
1596 set_environment(nullptr); | 1629 set_environment(nullptr); |
1597 } | 1630 } |
1598 | 1631 |
| 1632 void BytecodeGraphBuilder::BuildLoopExitsForBranch(int target_offset) { |
| 1633 int origin_offset = bytecode_iterator().current_offset(); |
| 1634 // Only build loop exits for forward edges. |
| 1635 if (target_offset > origin_offset) { |
| 1636 BuildLoopExitsUntilLoop(loop_analysis()->GetLoopOffsetFor(target_offset)); |
| 1637 } |
| 1638 } |
| 1639 |
| 1640 void BytecodeGraphBuilder::BuildLoopExitsUntilLoop(int loop_offset) { |
| 1641 int origin_offset = bytecode_iterator().current_offset(); |
| 1642 int current_loop = loop_analysis()->GetLoopOffsetFor(origin_offset); |
| 1643 while (loop_offset < current_loop) { |
| 1644 Node* loop_node = merge_environments_[current_loop]->GetControlDependency(); |
| 1645 environment()->PrepareForLoopExit(loop_node); |
| 1646 current_loop = loop_analysis()->GetParentLoopFor(current_loop); |
| 1647 } |
| 1648 } |
| 1649 |
| 1650 void BytecodeGraphBuilder::BuildLoopExitsForFunctionExit() { |
| 1651 BuildLoopExitsUntilLoop(-1); |
| 1652 } |
| 1653 |
1599 void BytecodeGraphBuilder::BuildJump() { | 1654 void BytecodeGraphBuilder::BuildJump() { |
1600 MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); | 1655 MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); |
1601 } | 1656 } |
1602 | 1657 |
1603 | 1658 |
1604 void BytecodeGraphBuilder::BuildConditionalJump(Node* condition) { | 1659 void BytecodeGraphBuilder::BuildConditionalJump(Node* condition) { |
1605 NewBranch(condition); | 1660 NewBranch(condition); |
1606 Environment* if_false_environment = environment()->CopyForConditional(); | 1661 Environment* if_false_environment = environment()->CopyForConditional(); |
1607 NewIfTrue(); | 1662 NewIfTrue(); |
1608 MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); | 1663 MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1823 // Phi does not exist yet, introduce one. | 1878 // Phi does not exist yet, introduce one. |
1824 value = NewPhi(inputs, value, control); | 1879 value = NewPhi(inputs, value, control); |
1825 value->ReplaceInput(inputs - 1, other); | 1880 value->ReplaceInput(inputs - 1, other); |
1826 } | 1881 } |
1827 return value; | 1882 return value; |
1828 } | 1883 } |
1829 | 1884 |
1830 } // namespace compiler | 1885 } // namespace compiler |
1831 } // namespace internal | 1886 } // namespace internal |
1832 } // namespace v8 | 1887 } // namespace v8 |
OLD | NEW |