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 |