| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/load-elimination.h" | 5 #include "src/compiler/load-elimination.h" |
| 6 | 6 |
| 7 #include "src/compiler/common-operator.h" | 7 #include "src/compiler/common-operator.h" |
| 8 #include "src/compiler/js-graph.h" | 8 #include "src/compiler/js-graph.h" |
| 9 #include "src/compiler/node-properties.h" | 9 #include "src/compiler/node-properties.h" |
| 10 #include "src/compiler/simplified-operator.h" | 10 #include "src/compiler/simplified-operator.h" |
| (...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 state = state->AddCheck(node, zone()); | 498 state = state->AddCheck(node, zone()); |
| 499 return UpdateState(node, state); | 499 return UpdateState(node, state); |
| 500 } | 500 } |
| 501 | 501 |
| 502 Reduction LoadElimination::ReduceCheckMaps(Node* node) { | 502 Reduction LoadElimination::ReduceCheckMaps(Node* node) { |
| 503 Node* const object = NodeProperties::GetValueInput(node, 0); | 503 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 504 Node* const effect = NodeProperties::GetEffectInput(node); | 504 Node* const effect = NodeProperties::GetEffectInput(node); |
| 505 AbstractState const* state = node_states_.Get(effect); | 505 AbstractState const* state = node_states_.Get(effect); |
| 506 if (state == nullptr) return NoChange(); | 506 if (state == nullptr) return NoChange(); |
| 507 int const map_input_count = node->op()->ValueInputCount() - 1; | 507 int const map_input_count = node->op()->ValueInputCount() - 1; |
| 508 if (Node* const object_map = state->LookupField(object, 0)) { | 508 if (Node* const object_map = |
| 509 state->LookupField(object, FieldIndexOf(HeapObject::kMapOffset))) { |
| 509 for (int i = 0; i < map_input_count; ++i) { | 510 for (int i = 0; i < map_input_count; ++i) { |
| 510 Node* map = NodeProperties::GetValueInput(node, 1 + i); | 511 Node* map = NodeProperties::GetValueInput(node, 1 + i); |
| 511 if (map == object_map) return Replace(effect); | 512 if (map == object_map) return Replace(effect); |
| 512 } | 513 } |
| 513 } | 514 } |
| 514 if (map_input_count == 1) { | 515 if (map_input_count == 1) { |
| 515 Node* const map0 = NodeProperties::GetValueInput(node, 1); | 516 Node* const map0 = NodeProperties::GetValueInput(node, 1); |
| 516 state = state->AddField(object, 0, map0, zone()); | 517 state = state->AddField(object, FieldIndexOf(HeapObject::kMapOffset), map0, |
| 518 zone()); |
| 517 } | 519 } |
| 518 return UpdateState(node, state); | 520 return UpdateState(node, state); |
| 519 } | 521 } |
| 520 | 522 |
| 521 Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) { | 523 Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) { |
| 522 Node* const object = NodeProperties::GetValueInput(node, 0); | 524 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 523 Node* const elements = NodeProperties::GetValueInput(node, 1); | 525 Node* const elements = NodeProperties::GetValueInput(node, 1); |
| 524 Node* const effect = NodeProperties::GetEffectInput(node); | 526 Node* const effect = NodeProperties::GetEffectInput(node); |
| 525 AbstractState const* state = node_states_.Get(effect); | 527 AbstractState const* state = node_states_.Get(effect); |
| 526 if (state == nullptr) return NoChange(); | 528 if (state == nullptr) return NoChange(); |
| 527 Node* fixed_array_map = jsgraph()->FixedArrayMapConstant(); | 529 Node* fixed_array_map = jsgraph()->FixedArrayMapConstant(); |
| 528 if (Node* const elements_map = state->LookupField(elements, 0)) { | 530 if (Node* const elements_map = |
| 531 state->LookupField(elements, FieldIndexOf(HeapObject::kMapOffset))) { |
| 529 // Check if the {elements} already have the fixed array map. | 532 // Check if the {elements} already have the fixed array map. |
| 530 if (elements_map == fixed_array_map) { | 533 if (elements_map == fixed_array_map) { |
| 531 ReplaceWithValue(node, elements, effect); | 534 ReplaceWithValue(node, elements, effect); |
| 532 return Replace(elements); | 535 return Replace(elements); |
| 533 } | 536 } |
| 534 } | 537 } |
| 535 // We know that the resulting elements have the fixed array map. | 538 // We know that the resulting elements have the fixed array map. |
| 536 state = state->AddField(node, 0, fixed_array_map, zone()); | 539 state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), |
| 540 fixed_array_map, zone()); |
| 537 // Kill the previous elements on {object}. | 541 // Kill the previous elements on {object}. |
| 538 state = state->KillField(object, 2, zone()); | 542 state = |
| 543 state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
| 539 // Add the new elements on {object}. | 544 // Add the new elements on {object}. |
| 540 state = state->AddField(object, 2, node, zone()); | 545 state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node, |
| 546 zone()); |
| 541 return UpdateState(node, state); | 547 return UpdateState(node, state); |
| 542 } | 548 } |
| 543 | 549 |
| 544 Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) { | 550 Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) { |
| 545 GrowFastElementsFlags flags = GrowFastElementsFlagsOf(node->op()); | 551 GrowFastElementsFlags flags = GrowFastElementsFlagsOf(node->op()); |
| 546 Node* const object = NodeProperties::GetValueInput(node, 0); | 552 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 547 Node* const effect = NodeProperties::GetEffectInput(node); | 553 Node* const effect = NodeProperties::GetEffectInput(node); |
| 548 AbstractState const* state = node_states_.Get(effect); | 554 AbstractState const* state = node_states_.Get(effect); |
| 549 if (state == nullptr) return NoChange(); | 555 if (state == nullptr) return NoChange(); |
| 550 if (flags & GrowFastElementsFlag::kDoubleElements) { | 556 if (flags & GrowFastElementsFlag::kDoubleElements) { |
| 551 // We know that the resulting elements have the fixed double array map. | 557 // We know that the resulting elements have the fixed double array map. |
| 552 Node* fixed_double_array_map = jsgraph()->FixedDoubleArrayMapConstant(); | 558 Node* fixed_double_array_map = jsgraph()->FixedDoubleArrayMapConstant(); |
| 553 state = state->AddField(node, 0, fixed_double_array_map, zone()); | 559 state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), |
| 560 fixed_double_array_map, zone()); |
| 554 } else { | 561 } else { |
| 555 // We know that the resulting elements have the fixed array map. | 562 // We know that the resulting elements have the fixed array map. |
| 556 Node* fixed_array_map = jsgraph()->FixedArrayMapConstant(); | 563 Node* fixed_array_map = jsgraph()->FixedArrayMapConstant(); |
| 557 state = state->AddField(node, 0, fixed_array_map, zone()); | 564 state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), |
| 565 fixed_array_map, zone()); |
| 558 } | 566 } |
| 559 if (flags & GrowFastElementsFlag::kArrayObject) { | 567 if (flags & GrowFastElementsFlag::kArrayObject) { |
| 560 // Kill the previous Array::length on {object}. | 568 // Kill the previous Array::length on {object}. |
| 561 state = state->KillField(object, 3, zone()); | 569 state = |
| 570 state->KillField(object, FieldIndexOf(JSArray::kLengthOffset), zone()); |
| 562 } | 571 } |
| 563 // Kill the previous elements on {object}. | 572 // Kill the previous elements on {object}. |
| 564 state = state->KillField(object, 2, zone()); | 573 state = |
| 574 state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
| 565 // Add the new elements on {object}. | 575 // Add the new elements on {object}. |
| 566 state = state->AddField(object, 2, node, zone()); | 576 state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node, |
| 577 zone()); |
| 567 return UpdateState(node, state); | 578 return UpdateState(node, state); |
| 568 } | 579 } |
| 569 | 580 |
| 570 Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) { | 581 Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) { |
| 571 Node* const object = NodeProperties::GetValueInput(node, 0); | 582 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 572 Node* const source_map = NodeProperties::GetValueInput(node, 1); | 583 Node* const source_map = NodeProperties::GetValueInput(node, 1); |
| 573 Node* const target_map = NodeProperties::GetValueInput(node, 2); | 584 Node* const target_map = NodeProperties::GetValueInput(node, 2); |
| 574 Node* const effect = NodeProperties::GetEffectInput(node); | 585 Node* const effect = NodeProperties::GetEffectInput(node); |
| 575 AbstractState const* state = node_states_.Get(effect); | 586 AbstractState const* state = node_states_.Get(effect); |
| 576 if (state == nullptr) return NoChange(); | 587 if (state == nullptr) return NoChange(); |
| 577 if (Node* const object_map = state->LookupField(object, 0)) { | 588 if (Node* const object_map = |
| 589 state->LookupField(object, FieldIndexOf(HeapObject::kMapOffset))) { |
| 578 if (target_map == object_map) { | 590 if (target_map == object_map) { |
| 579 // The {object} already has the {target_map}, so this TransitionElements | 591 // The {object} already has the {target_map}, so this TransitionElements |
| 580 // {node} is fully redundant (independent of what {source_map} is). | 592 // {node} is fully redundant (independent of what {source_map} is). |
| 581 return Replace(effect); | 593 return Replace(effect); |
| 582 } | 594 } |
| 583 state = state->KillField(object, 0, zone()); | 595 state = |
| 596 state->KillField(object, FieldIndexOf(HeapObject::kMapOffset), zone()); |
| 584 if (source_map == object_map) { | 597 if (source_map == object_map) { |
| 585 state = state->AddField(object, 0, target_map, zone()); | 598 state = state->AddField(object, FieldIndexOf(HeapObject::kMapOffset), |
| 599 target_map, zone()); |
| 586 } | 600 } |
| 587 } else { | 601 } else { |
| 588 state = state->KillField(object, 0, zone()); | 602 state = |
| 603 state->KillField(object, FieldIndexOf(HeapObject::kMapOffset), zone()); |
| 589 } | 604 } |
| 590 ElementsTransition transition = ElementsTransitionOf(node->op()); | 605 ElementsTransition transition = ElementsTransitionOf(node->op()); |
| 591 switch (transition) { | 606 switch (transition) { |
| 592 case ElementsTransition::kFastTransition: | 607 case ElementsTransition::kFastTransition: |
| 593 break; | 608 break; |
| 594 case ElementsTransition::kSlowTransition: | 609 case ElementsTransition::kSlowTransition: |
| 595 // Kill the elements as well. | 610 // Kill the elements as well. |
| 596 state = state->KillField(object, 2, zone()); | 611 state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), |
| 612 zone()); |
| 597 break; | 613 break; |
| 598 } | 614 } |
| 599 return UpdateState(node, state); | 615 return UpdateState(node, state); |
| 600 } | 616 } |
| 601 | 617 |
| 602 Reduction LoadElimination::ReduceLoadField(Node* node) { | 618 Reduction LoadElimination::ReduceLoadField(Node* node) { |
| 603 FieldAccess const& access = FieldAccessOf(node->op()); | 619 FieldAccess const& access = FieldAccessOf(node->op()); |
| 604 Node* const object = NodeProperties::GetValueInput(node, 0); | 620 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 605 Node* const effect = NodeProperties::GetEffectInput(node); | 621 Node* const effect = NodeProperties::GetEffectInput(node); |
| 606 Node* const control = NodeProperties::GetControlInput(node); | 622 Node* const control = NodeProperties::GetControlInput(node); |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 805 } | 821 } |
| 806 while (!queue.empty()) { | 822 while (!queue.empty()) { |
| 807 Node* const current = queue.front(); | 823 Node* const current = queue.front(); |
| 808 queue.pop(); | 824 queue.pop(); |
| 809 if (visited.find(current) == visited.end()) { | 825 if (visited.find(current) == visited.end()) { |
| 810 visited.insert(current); | 826 visited.insert(current); |
| 811 if (!current->op()->HasProperty(Operator::kNoWrite)) { | 827 if (!current->op()->HasProperty(Operator::kNoWrite)) { |
| 812 switch (current->opcode()) { | 828 switch (current->opcode()) { |
| 813 case IrOpcode::kEnsureWritableFastElements: { | 829 case IrOpcode::kEnsureWritableFastElements: { |
| 814 Node* const object = NodeProperties::GetValueInput(current, 0); | 830 Node* const object = NodeProperties::GetValueInput(current, 0); |
| 815 state = state->KillField(object, 2, zone()); | 831 state = state->KillField( |
| 832 object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
| 816 break; | 833 break; |
| 817 } | 834 } |
| 818 case IrOpcode::kMaybeGrowFastElements: { | 835 case IrOpcode::kMaybeGrowFastElements: { |
| 819 GrowFastElementsFlags flags = | 836 GrowFastElementsFlags flags = |
| 820 GrowFastElementsFlagsOf(current->op()); | 837 GrowFastElementsFlagsOf(current->op()); |
| 821 Node* const object = NodeProperties::GetValueInput(current, 0); | 838 Node* const object = NodeProperties::GetValueInput(current, 0); |
| 822 state = state->KillField(object, 2, zone()); | 839 state = state->KillField( |
| 840 object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
| 823 if (flags & GrowFastElementsFlag::kArrayObject) { | 841 if (flags & GrowFastElementsFlag::kArrayObject) { |
| 824 state = state->KillField(object, 3, zone()); | 842 state = state->KillField( |
| 843 object, FieldIndexOf(JSArray::kLengthOffset), zone()); |
| 825 } | 844 } |
| 826 break; | 845 break; |
| 827 } | 846 } |
| 828 case IrOpcode::kTransitionElementsKind: { | 847 case IrOpcode::kTransitionElementsKind: { |
| 829 Node* const object = NodeProperties::GetValueInput(current, 0); | 848 Node* const object = NodeProperties::GetValueInput(current, 0); |
| 830 state = state->KillField(object, 0, zone()); | 849 state = state->KillField( |
| 831 state = state->KillField(object, 2, zone()); | 850 object, FieldIndexOf(HeapObject::kMapOffset), zone()); |
| 851 state = state->KillField( |
| 852 object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
| 832 break; | 853 break; |
| 833 } | 854 } |
| 834 case IrOpcode::kStoreField: { | 855 case IrOpcode::kStoreField: { |
| 835 FieldAccess const& access = FieldAccessOf(current->op()); | 856 FieldAccess const& access = FieldAccessOf(current->op()); |
| 836 Node* const object = NodeProperties::GetValueInput(current, 0); | 857 Node* const object = NodeProperties::GetValueInput(current, 0); |
| 837 int field_index = FieldIndexOf(access); | 858 int field_index = FieldIndexOf(access); |
| 838 if (field_index < 0) return empty_state(); | 859 if (field_index < 0) return empty_state(); |
| 839 state = state->KillField(object, field_index, zone()); | 860 state = state->KillField(object, field_index, zone()); |
| 840 break; | 861 break; |
| 841 } | 862 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 856 } | 877 } |
| 857 for (int i = 0; i < current->op()->EffectInputCount(); ++i) { | 878 for (int i = 0; i < current->op()->EffectInputCount(); ++i) { |
| 858 queue.push(NodeProperties::GetEffectInput(current, i)); | 879 queue.push(NodeProperties::GetEffectInput(current, i)); |
| 859 } | 880 } |
| 860 } | 881 } |
| 861 } | 882 } |
| 862 return state; | 883 return state; |
| 863 } | 884 } |
| 864 | 885 |
| 865 // static | 886 // static |
| 887 int LoadElimination::FieldIndexOf(int offset) { |
| 888 DCHECK_EQ(0, offset % kPointerSize); |
| 889 int field_index = offset / kPointerSize; |
| 890 if (field_index >= static_cast<int>(kMaxTrackedFields)) return -1; |
| 891 return field_index; |
| 892 } |
| 893 |
| 894 // static |
| 866 int LoadElimination::FieldIndexOf(FieldAccess const& access) { | 895 int LoadElimination::FieldIndexOf(FieldAccess const& access) { |
| 867 MachineRepresentation rep = access.machine_type.representation(); | 896 MachineRepresentation rep = access.machine_type.representation(); |
| 868 switch (rep) { | 897 switch (rep) { |
| 869 case MachineRepresentation::kNone: | 898 case MachineRepresentation::kNone: |
| 870 case MachineRepresentation::kBit: | 899 case MachineRepresentation::kBit: |
| 871 UNREACHABLE(); | 900 UNREACHABLE(); |
| 872 break; | 901 break; |
| 873 case MachineRepresentation::kWord32: | 902 case MachineRepresentation::kWord32: |
| 874 case MachineRepresentation::kWord64: | 903 case MachineRepresentation::kWord64: |
| 875 if (rep != MachineType::PointerRepresentation()) { | 904 if (rep != MachineType::PointerRepresentation()) { |
| 876 return -1; // We currently only track pointer size fields. | 905 return -1; // We currently only track pointer size fields. |
| 877 } | 906 } |
| 878 break; | 907 break; |
| 879 case MachineRepresentation::kWord8: | 908 case MachineRepresentation::kWord8: |
| 880 case MachineRepresentation::kWord16: | 909 case MachineRepresentation::kWord16: |
| 881 case MachineRepresentation::kFloat32: | 910 case MachineRepresentation::kFloat32: |
| 882 return -1; // Currently untracked. | 911 return -1; // Currently untracked. |
| 883 case MachineRepresentation::kFloat64: | 912 case MachineRepresentation::kFloat64: |
| 884 case MachineRepresentation::kSimd128: | 913 case MachineRepresentation::kSimd128: |
| 885 return -1; // Currently untracked. | 914 return -1; // Currently untracked. |
| 886 case MachineRepresentation::kTaggedSigned: | 915 case MachineRepresentation::kTaggedSigned: |
| 887 case MachineRepresentation::kTaggedPointer: | 916 case MachineRepresentation::kTaggedPointer: |
| 888 case MachineRepresentation::kTagged: | 917 case MachineRepresentation::kTagged: |
| 889 // TODO(bmeurer): Check that we never do overlapping load/stores of | 918 // TODO(bmeurer): Check that we never do overlapping load/stores of |
| 890 // individual parts of Float64/Simd128 values. | 919 // individual parts of Float64/Simd128 values. |
| 891 break; | 920 break; |
| 892 } | 921 } |
| 893 DCHECK_EQ(kTaggedBase, access.base_is_tagged); | 922 DCHECK_EQ(kTaggedBase, access.base_is_tagged); |
| 894 DCHECK_EQ(0, access.offset % kPointerSize); | 923 return FieldIndexOf(access.offset); |
| 895 int field_index = access.offset / kPointerSize; | |
| 896 if (field_index >= static_cast<int>(kMaxTrackedFields)) return -1; | |
| 897 return field_index; | |
| 898 } | 924 } |
| 899 | 925 |
| 900 CommonOperatorBuilder* LoadElimination::common() const { | 926 CommonOperatorBuilder* LoadElimination::common() const { |
| 901 return jsgraph()->common(); | 927 return jsgraph()->common(); |
| 902 } | 928 } |
| 903 | 929 |
| 904 Graph* LoadElimination::graph() const { return jsgraph()->graph(); } | 930 Graph* LoadElimination::graph() const { return jsgraph()->graph(); } |
| 905 | 931 |
| 906 } // namespace compiler | 932 } // namespace compiler |
| 907 } // namespace internal | 933 } // namespace internal |
| 908 } // namespace v8 | 934 } // namespace v8 |
| OLD | NEW |