OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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/js-builtin-reducer.h" | 5 #include "src/compiler/js-builtin-reducer.h" |
6 | 6 |
7 #include "src/compiler/access-builder.h" | 7 #include "src/compiler/access-builder.h" |
8 #include "src/compiler/js-graph.h" | 8 #include "src/compiler/js-graph.h" |
9 #include "src/compiler/node-matchers.h" | 9 #include "src/compiler/node-matchers.h" |
10 #include "src/compiler/node-properties.h" | 10 #include "src/compiler/node-properties.h" |
(...skipping 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
536 // String.fromCharCode(a:plain-primitive) -> StringFromCharCode(a) | 536 // String.fromCharCode(a:plain-primitive) -> StringFromCharCode(a) |
537 Node* input = ToNumber(r.GetJSCallInput(0)); | 537 Node* input = ToNumber(r.GetJSCallInput(0)); |
538 Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input); | 538 Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input); |
539 return Replace(value); | 539 return Replace(value); |
540 } | 540 } |
541 return NoChange(); | 541 return NoChange(); |
542 } | 542 } |
543 | 543 |
544 namespace { | 544 namespace { |
545 | 545 |
546 Node* GetStringReceiver(Node* node) { | 546 Node* GetStringWitness(Node* node) { |
547 Node* receiver = NodeProperties::GetValueInput(node, 1); | 547 Node* receiver = NodeProperties::GetValueInput(node, 1); |
548 Type* receiver_type = NodeProperties::GetType(receiver); | 548 Type* receiver_type = NodeProperties::GetType(receiver); |
549 Node* effect = NodeProperties::GetEffectInput(node); | 549 Node* effect = NodeProperties::GetEffectInput(node); |
550 if (receiver_type->Is(Type::String())) return receiver; | 550 if (receiver_type->Is(Type::String())) return receiver; |
551 // Check if the {node} is dominated by a CheckString renaming for | 551 // Check if the {node} is dominated by a CheckString renaming for |
552 // it's {receiver}, and if so use that renaming as {receiver} for | 552 // it's {receiver}, and if so use that renaming as {receiver} for |
553 // the lowering below. | 553 // the lowering below. |
554 for (Node* dominator = effect;;) { | 554 for (Node* dominator = effect;;) { |
555 if (dominator->opcode() == IrOpcode::kCheckString && | 555 if (dominator->opcode() == IrOpcode::kCheckString && |
556 dominator->InputAt(0) == receiver) { | 556 dominator->InputAt(0) == receiver) { |
(...skipping 12 matching lines...) Expand all Loading... |
569 // ES6 section 21.1.3.1 String.prototype.charAt ( pos ) | 569 // ES6 section 21.1.3.1 String.prototype.charAt ( pos ) |
570 Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) { | 570 Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) { |
571 // We need at least target, receiver and index parameters. | 571 // We need at least target, receiver and index parameters. |
572 if (node->op()->ValueInputCount() >= 3) { | 572 if (node->op()->ValueInputCount() >= 3) { |
573 Node* index = NodeProperties::GetValueInput(node, 2); | 573 Node* index = NodeProperties::GetValueInput(node, 2); |
574 Type* index_type = NodeProperties::GetType(index); | 574 Type* index_type = NodeProperties::GetType(index); |
575 Node* effect = NodeProperties::GetEffectInput(node); | 575 Node* effect = NodeProperties::GetEffectInput(node); |
576 Node* control = NodeProperties::GetControlInput(node); | 576 Node* control = NodeProperties::GetControlInput(node); |
577 | 577 |
578 if (index_type->Is(Type::Unsigned32())) { | 578 if (index_type->Is(Type::Unsigned32())) { |
579 if (Node* receiver = GetStringReceiver(node)) { | 579 if (Node* receiver = GetStringWitness(node)) { |
580 // Determine the {receiver} length. | 580 // Determine the {receiver} length. |
581 Node* receiver_length = effect = graph()->NewNode( | 581 Node* receiver_length = effect = graph()->NewNode( |
582 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, | 582 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, |
583 effect, control); | 583 effect, control); |
584 | 584 |
585 // Check if {index} is less than {receiver} length. | 585 // Check if {index} is less than {receiver} length. |
586 Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, | 586 Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, |
587 receiver_length); | 587 receiver_length); |
588 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), | 588 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
589 check, control); | 589 check, control); |
(...skipping 30 matching lines...) Expand all Loading... |
620 // ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos ) | 620 // ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos ) |
621 Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) { | 621 Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) { |
622 // We need at least target, receiver and index parameters. | 622 // We need at least target, receiver and index parameters. |
623 if (node->op()->ValueInputCount() >= 3) { | 623 if (node->op()->ValueInputCount() >= 3) { |
624 Node* index = NodeProperties::GetValueInput(node, 2); | 624 Node* index = NodeProperties::GetValueInput(node, 2); |
625 Type* index_type = NodeProperties::GetType(index); | 625 Type* index_type = NodeProperties::GetType(index); |
626 Node* effect = NodeProperties::GetEffectInput(node); | 626 Node* effect = NodeProperties::GetEffectInput(node); |
627 Node* control = NodeProperties::GetControlInput(node); | 627 Node* control = NodeProperties::GetControlInput(node); |
628 | 628 |
629 if (index_type->Is(Type::Unsigned32())) { | 629 if (index_type->Is(Type::Unsigned32())) { |
630 if (Node* receiver = GetStringReceiver(node)) { | 630 if (Node* receiver = GetStringWitness(node)) { |
631 // Determine the {receiver} length. | 631 // Determine the {receiver} length. |
632 Node* receiver_length = effect = graph()->NewNode( | 632 Node* receiver_length = effect = graph()->NewNode( |
633 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, | 633 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, |
634 effect, control); | 634 effect, control); |
635 | 635 |
636 // Check if {index} is less than {receiver} length. | 636 // Check if {index} is less than {receiver} length. |
637 Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, | 637 Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, |
638 receiver_length); | 638 receiver_length); |
639 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), | 639 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
640 check, control); | 640 check, control); |
(...skipping 14 matching lines...) Expand all Loading... |
655 | 655 |
656 ReplaceWithValue(node, value, effect, control); | 656 ReplaceWithValue(node, value, effect, control); |
657 return Replace(value); | 657 return Replace(value); |
658 } | 658 } |
659 } | 659 } |
660 } | 660 } |
661 | 661 |
662 return NoChange(); | 662 return NoChange(); |
663 } | 663 } |
664 | 664 |
| 665 namespace { |
| 666 |
| 667 bool HasInstanceTypeWitness(Node* receiver, Node* effect, |
| 668 InstanceType instance_type) { |
| 669 for (Node* dominator = effect;;) { |
| 670 if (dominator->opcode() == IrOpcode::kCheckMaps && |
| 671 dominator->InputAt(0) == receiver) { |
| 672 // Check if all maps have the given {instance_type}. |
| 673 for (int i = 1; i < dominator->op()->ValueInputCount(); ++i) { |
| 674 Node* const map = NodeProperties::GetValueInput(dominator, i); |
| 675 Type* const map_type = NodeProperties::GetType(map); |
| 676 if (!map_type->IsConstant()) return false; |
| 677 Handle<Map> const map_value = |
| 678 Handle<Map>::cast(map_type->AsConstant()->Value()); |
| 679 if (map_value->instance_type() != instance_type) return false; |
| 680 } |
| 681 return true; |
| 682 } |
| 683 switch (dominator->opcode()) { |
| 684 case IrOpcode::kStoreField: { |
| 685 FieldAccess const& access = FieldAccessOf(dominator->op()); |
| 686 if (access.base_is_tagged == kTaggedBase && |
| 687 access.offset == HeapObject::kMapOffset) { |
| 688 return false; |
| 689 } |
| 690 break; |
| 691 } |
| 692 case IrOpcode::kStoreElement: |
| 693 break; |
| 694 default: { |
| 695 DCHECK_EQ(1, dominator->op()->EffectOutputCount()); |
| 696 if (dominator->op()->EffectInputCount() != 1 || |
| 697 !dominator->op()->HasProperty(Operator::kNoWrite)) { |
| 698 // Didn't find any appropriate CheckMaps node. |
| 699 return false; |
| 700 } |
| 701 break; |
| 702 } |
| 703 } |
| 704 dominator = NodeProperties::GetEffectInput(dominator); |
| 705 } |
| 706 } |
| 707 |
| 708 } // namespace |
| 709 |
| 710 Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor( |
| 711 Node* node, InstanceType instance_type, FieldAccess const& access) { |
| 712 Node* receiver = NodeProperties::GetValueInput(node, 1); |
| 713 Node* effect = NodeProperties::GetEffectInput(node); |
| 714 Node* control = NodeProperties::GetControlInput(node); |
| 715 if (HasInstanceTypeWitness(receiver, effect, instance_type)) { |
| 716 // Load the {receiver}s field. |
| 717 Node* receiver_length = effect = graph()->NewNode( |
| 718 simplified()->LoadField(access), receiver, effect, control); |
| 719 |
| 720 // Check if the {receiver}s buffer was neutered. |
| 721 Node* receiver_buffer = effect = graph()->NewNode( |
| 722 simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), |
| 723 receiver, effect, control); |
| 724 Node* receiver_buffer_bitfield = effect = graph()->NewNode( |
| 725 simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()), |
| 726 receiver_buffer, effect, control); |
| 727 Node* check = graph()->NewNode( |
| 728 simplified()->NumberEqual(), |
| 729 graph()->NewNode( |
| 730 simplified()->NumberBitwiseAnd(), receiver_buffer_bitfield, |
| 731 jsgraph()->Constant(JSArrayBuffer::WasNeutered::kMask)), |
| 732 jsgraph()->ZeroConstant()); |
| 733 |
| 734 // Default to zero if the {receiver}s buffer was neutered. |
| 735 Node* value = |
| 736 graph()->NewNode(common()->Select(MachineRepresentation::kTagged), |
| 737 check, receiver_length, jsgraph()->ZeroConstant()); |
| 738 |
| 739 ReplaceWithValue(node, value, effect, control); |
| 740 return Replace(value); |
| 741 } |
| 742 return NoChange(); |
| 743 } |
| 744 |
665 Reduction JSBuiltinReducer::Reduce(Node* node) { | 745 Reduction JSBuiltinReducer::Reduce(Node* node) { |
666 Reduction reduction = NoChange(); | 746 Reduction reduction = NoChange(); |
667 JSCallReduction r(node); | 747 JSCallReduction r(node); |
668 | 748 |
669 // Dispatch according to the BuiltinFunctionId if present. | 749 // Dispatch according to the BuiltinFunctionId if present. |
670 if (!r.HasBuiltinFunctionId()) return NoChange(); | 750 if (!r.HasBuiltinFunctionId()) return NoChange(); |
671 switch (r.GetBuiltinFunctionId()) { | 751 switch (r.GetBuiltinFunctionId()) { |
672 case kMathAbs: | 752 case kMathAbs: |
673 reduction = ReduceMathAbs(node); | 753 reduction = ReduceMathAbs(node); |
674 break; | 754 break; |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
771 case kNumberParseInt: | 851 case kNumberParseInt: |
772 reduction = ReduceNumberParseInt(node); | 852 reduction = ReduceNumberParseInt(node); |
773 break; | 853 break; |
774 case kStringFromCharCode: | 854 case kStringFromCharCode: |
775 reduction = ReduceStringFromCharCode(node); | 855 reduction = ReduceStringFromCharCode(node); |
776 break; | 856 break; |
777 case kStringCharAt: | 857 case kStringCharAt: |
778 return ReduceStringCharAt(node); | 858 return ReduceStringCharAt(node); |
779 case kStringCharCodeAt: | 859 case kStringCharCodeAt: |
780 return ReduceStringCharCodeAt(node); | 860 return ReduceStringCharCodeAt(node); |
| 861 case kDataViewByteLength: |
| 862 return ReduceArrayBufferViewAccessor( |
| 863 node, JS_DATA_VIEW_TYPE, |
| 864 AccessBuilder::ForJSArrayBufferViewByteLength()); |
| 865 case kDataViewByteOffset: |
| 866 return ReduceArrayBufferViewAccessor( |
| 867 node, JS_DATA_VIEW_TYPE, |
| 868 AccessBuilder::ForJSArrayBufferViewByteOffset()); |
| 869 case kTypedArrayByteLength: |
| 870 return ReduceArrayBufferViewAccessor( |
| 871 node, JS_TYPED_ARRAY_TYPE, |
| 872 AccessBuilder::ForJSArrayBufferViewByteLength()); |
| 873 case kTypedArrayByteOffset: |
| 874 return ReduceArrayBufferViewAccessor( |
| 875 node, JS_TYPED_ARRAY_TYPE, |
| 876 AccessBuilder::ForJSArrayBufferViewByteOffset()); |
| 877 case kTypedArrayLength: |
| 878 return ReduceArrayBufferViewAccessor( |
| 879 node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength()); |
781 default: | 880 default: |
782 break; | 881 break; |
783 } | 882 } |
784 | 883 |
785 // Replace builtin call assuming replacement nodes are pure values that don't | 884 // Replace builtin call assuming replacement nodes are pure values that don't |
786 // produce an effect. Replaces {node} with {reduction} and relaxes effects. | 885 // produce an effect. Replaces {node} with {reduction} and relaxes effects. |
787 if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement()); | 886 if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement()); |
788 | 887 |
789 return reduction; | 888 return reduction; |
790 } | 889 } |
(...skipping 22 matching lines...) Expand all Loading... |
813 } | 912 } |
814 | 913 |
815 | 914 |
816 SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const { | 915 SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const { |
817 return jsgraph()->simplified(); | 916 return jsgraph()->simplified(); |
818 } | 917 } |
819 | 918 |
820 } // namespace compiler | 919 } // namespace compiler |
821 } // namespace internal | 920 } // namespace internal |
822 } // namespace v8 | 921 } // namespace v8 |
OLD | NEW |