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/access-builder.h" | 5 #include "src/compiler/access-builder.h" |
6 #include "src/compiler/graph-inl.h" | 6 #include "src/compiler/graph-inl.h" |
7 #include "src/compiler/js-builtin-reducer.h" | 7 #include "src/compiler/js-builtin-reducer.h" |
8 #include "src/compiler/js-typed-lowering.h" | 8 #include "src/compiler/js-typed-lowering.h" |
9 #include "src/compiler/node-aux-data-inl.h" | 9 #include "src/compiler/node-aux-data-inl.h" |
| 10 #include "src/compiler/node-matchers.h" |
10 #include "src/compiler/node-properties-inl.h" | 11 #include "src/compiler/node-properties-inl.h" |
11 #include "src/types.h" | 12 #include "src/types.h" |
12 | 13 |
13 namespace v8 { | 14 namespace v8 { |
14 namespace internal { | 15 namespace internal { |
15 namespace compiler { | 16 namespace compiler { |
16 | 17 |
17 // TODO(turbofan): js-typed-lowering improvements possible | 18 // TODO(turbofan): js-typed-lowering improvements possible |
18 // - immediately put in type bounds for all new nodes | 19 // - immediately put in type bounds for all new nodes |
19 // - relax effects from generic but not-side-effecting operations | 20 // - relax effects from generic but not-side-effecting operations |
(...skipping 11 matching lines...) Expand all Loading... |
31 | 32 |
32 JSTypedLowering::JSTypedLowering(JSGraph* jsgraph) | 33 JSTypedLowering::JSTypedLowering(JSGraph* jsgraph) |
33 : jsgraph_(jsgraph), simplified_(jsgraph->zone()) { | 34 : jsgraph_(jsgraph), simplified_(jsgraph->zone()) { |
34 Factory* factory = zone()->isolate()->factory(); | 35 Factory* factory = zone()->isolate()->factory(); |
35 Handle<Object> zero = factory->NewNumber(0.0); | 36 Handle<Object> zero = factory->NewNumber(0.0); |
36 Handle<Object> one = factory->NewNumber(1.0); | 37 Handle<Object> one = factory->NewNumber(1.0); |
37 zero_range_ = Type::Range(zero, zero, zone()); | 38 zero_range_ = Type::Range(zero, zero, zone()); |
38 one_range_ = Type::Range(one, one, zone()); | 39 one_range_ = Type::Range(one, one, zone()); |
39 Handle<Object> thirtyone = factory->NewNumber(31.0); | 40 Handle<Object> thirtyone = factory->NewNumber(31.0); |
40 zero_thirtyone_range_ = Type::Range(zero, thirtyone, zone()); | 41 zero_thirtyone_range_ = Type::Range(zero, thirtyone, zone()); |
| 42 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) { |
| 43 Handle<Object> min = factory->NewNumber(kMinInt / (1 << k)); |
| 44 Handle<Object> max = factory->NewNumber(kMaxInt / (1 << k)); |
| 45 shifted_int32_ranges_[k] = Type::Range(min, max, zone()); |
| 46 } |
41 } | 47 } |
42 | 48 |
43 | 49 |
44 JSTypedLowering::~JSTypedLowering() {} | |
45 | |
46 | |
47 Reduction JSTypedLowering::ReplaceEagerly(Node* old, Node* node) { | 50 Reduction JSTypedLowering::ReplaceEagerly(Node* old, Node* node) { |
48 NodeProperties::ReplaceWithValue(old, node, node); | 51 NodeProperties::ReplaceWithValue(old, node, node); |
49 return Changed(node); | 52 return Changed(node); |
50 } | 53 } |
51 | 54 |
52 | 55 |
53 // A helper class to simplify the process of reducing a single binop node with a | 56 // A helper class to simplify the process of reducing a single binop node with a |
54 // JSOperator. This class manages the rewriting of context, control, and effect | 57 // JSOperator. This class manages the rewriting of context, control, and effect |
55 // dependencies during lowering of a binop and contains numerous helper | 58 // dependencies during lowering of a binop and contains numerous helper |
56 // functions for matching the types of inputs to an operation. | 59 // functions for matching the types of inputs to an operation. |
(...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
667 } | 670 } |
668 | 671 |
669 | 672 |
670 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { | 673 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { |
671 Node* key = NodeProperties::GetValueInput(node, 1); | 674 Node* key = NodeProperties::GetValueInput(node, 1); |
672 Node* base = NodeProperties::GetValueInput(node, 0); | 675 Node* base = NodeProperties::GetValueInput(node, 0); |
673 Type* key_type = NodeProperties::GetBounds(key).upper; | 676 Type* key_type = NodeProperties::GetBounds(key).upper; |
674 Type* base_type = NodeProperties::GetBounds(base).upper; | 677 Type* base_type = NodeProperties::GetBounds(base).upper; |
675 // TODO(mstarzinger): This lowering is not correct if: | 678 // TODO(mstarzinger): This lowering is not correct if: |
676 // a) The typed array or it's buffer is neutered. | 679 // a) The typed array or it's buffer is neutered. |
677 if (base_type->IsConstant() && key_type->Is(Type::Integral32()) && | 680 if (base_type->IsConstant() && |
678 base_type->AsConstant()->Value()->IsJSTypedArray()) { | 681 base_type->AsConstant()->Value()->IsJSTypedArray()) { |
679 // JSLoadProperty(typed-array, int32) | 682 Handle<JSTypedArray> const array = |
680 Handle<JSTypedArray> array = | |
681 Handle<JSTypedArray>::cast(base_type->AsConstant()->Value()); | 683 Handle<JSTypedArray>::cast(base_type->AsConstant()->Value()); |
682 if (IsExternalArrayElementsKind(array->map()->elements_kind())) { | 684 BufferAccess const access(array->type()); |
683 ExternalArrayType type = array->type(); | 685 size_t const k = ElementSizeLog2Of(access.machine_type()); |
684 double byte_length = array->byte_length()->Number(); | 686 double const byte_length = array->byte_length()->Number(); |
685 if (byte_length <= kMaxInt) { | 687 CHECK_LT(k, arraysize(shifted_int32_ranges_)); |
686 Handle<ExternalArray> elements = | 688 if (IsExternalArrayElementsKind(array->map()->elements_kind()) && |
687 Handle<ExternalArray>::cast(handle(array->elements())); | 689 access.external_array_type() != kExternalUint8ClampedArray && |
688 Node* pointer = jsgraph()->IntPtrConstant( | 690 key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) { |
689 bit_cast<intptr_t>(elements->external_pointer())); | 691 // JSLoadProperty(typed-array, int32) |
690 Node* length = jsgraph()->Constant(array->length()->Number()); | 692 Handle<ExternalArray> elements = |
691 Node* effect = NodeProperties::GetEffectInput(node); | 693 Handle<ExternalArray>::cast(handle(array->elements())); |
| 694 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer()); |
| 695 Node* length = jsgraph()->Constant(byte_length); |
| 696 Node* effect = NodeProperties::GetEffectInput(node); |
| 697 Node* control = NodeProperties::GetControlInput(node); |
| 698 // Check if we can avoid the bounds check. |
| 699 if (key_type->Min() >= 0 && key_type->Max() < array->length()->Number()) { |
692 Node* load = graph()->NewNode( | 700 Node* load = graph()->NewNode( |
693 simplified()->LoadElement( | 701 simplified()->LoadElement( |
694 AccessBuilder::ForTypedArrayElement(type, true)), | 702 AccessBuilder::ForTypedArrayElement(array->type(), true)), |
695 pointer, key, length, effect); | 703 buffer, key, effect, control); |
696 return ReplaceEagerly(node, load); | 704 return ReplaceEagerly(node, load); |
697 } | 705 } |
| 706 // Compute byte offset. |
| 707 Node* offset = Word32Shl(key, static_cast<int>(k)); |
| 708 Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer, |
| 709 offset, length, effect, control); |
| 710 return ReplaceEagerly(node, load); |
698 } | 711 } |
699 } | 712 } |
700 return NoChange(); | 713 return NoChange(); |
701 } | 714 } |
702 | 715 |
703 | 716 |
704 Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { | 717 Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { |
705 Node* key = NodeProperties::GetValueInput(node, 1); | 718 Node* key = NodeProperties::GetValueInput(node, 1); |
706 Node* base = NodeProperties::GetValueInput(node, 0); | 719 Node* base = NodeProperties::GetValueInput(node, 0); |
707 Node* value = NodeProperties::GetValueInput(node, 2); | 720 Node* value = NodeProperties::GetValueInput(node, 2); |
708 Type* key_type = NodeProperties::GetBounds(key).upper; | 721 Type* key_type = NodeProperties::GetBounds(key).upper; |
709 Type* base_type = NodeProperties::GetBounds(base).upper; | 722 Type* base_type = NodeProperties::GetBounds(base).upper; |
| 723 Type* value_type = NodeProperties::GetBounds(value).upper; |
710 // TODO(mstarzinger): This lowering is not correct if: | 724 // TODO(mstarzinger): This lowering is not correct if: |
711 // a) The typed array or its buffer is neutered. | 725 // a) The typed array or its buffer is neutered. |
712 if (key_type->Is(Type::Integral32()) && base_type->IsConstant() && | 726 if (base_type->IsConstant() && |
713 base_type->AsConstant()->Value()->IsJSTypedArray()) { | 727 base_type->AsConstant()->Value()->IsJSTypedArray()) { |
714 // JSStoreProperty(typed-array, int32, value) | 728 Handle<JSTypedArray> const array = |
715 Handle<JSTypedArray> array = | |
716 Handle<JSTypedArray>::cast(base_type->AsConstant()->Value()); | 729 Handle<JSTypedArray>::cast(base_type->AsConstant()->Value()); |
717 if (IsExternalArrayElementsKind(array->map()->elements_kind())) { | 730 BufferAccess const access(array->type()); |
718 ExternalArrayType type = array->type(); | 731 size_t const k = ElementSizeLog2Of(access.machine_type()); |
719 double byte_length = array->byte_length()->Number(); | 732 double const byte_length = array->byte_length()->Number(); |
720 if (byte_length <= kMaxInt) { | 733 CHECK_LT(k, arraysize(shifted_int32_ranges_)); |
721 Handle<ExternalArray> elements = | 734 if (IsExternalArrayElementsKind(array->map()->elements_kind()) && |
722 Handle<ExternalArray>::cast(handle(array->elements())); | 735 access.external_array_type() != kExternalUint8ClampedArray && |
723 Node* pointer = jsgraph()->IntPtrConstant( | 736 key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) { |
724 bit_cast<intptr_t>(elements->external_pointer())); | 737 // JSLoadProperty(typed-array, int32) |
725 Node* length = jsgraph()->Constant(array->length()->Number()); | 738 Handle<ExternalArray> elements = |
726 Node* effect = NodeProperties::GetEffectInput(node); | 739 Handle<ExternalArray>::cast(handle(array->elements())); |
727 Node* control = NodeProperties::GetControlInput(node); | 740 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer()); |
728 | 741 Node* length = jsgraph()->Constant(byte_length); |
729 ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true); | 742 Node* context = NodeProperties::GetContextInput(node); |
730 Type* value_type = NodeProperties::GetBounds(value).upper; | 743 Node* effect = NodeProperties::GetEffectInput(node); |
731 // If the value input does not have the required type, insert the | 744 Node* control = NodeProperties::GetControlInput(node); |
732 // appropriate conversion. | 745 // Convert to a number first. |
733 | 746 if (!value_type->Is(Type::Number())) { |
734 // Convert to a number first. | 747 Reduction number_reduction = ReduceJSToNumberInput(value); |
735 if (!value_type->Is(Type::Number())) { | 748 if (number_reduction.Changed()) { |
736 Reduction number_reduction = ReduceJSToNumberInput(value); | 749 value = number_reduction.replacement(); |
737 if (number_reduction.Changed()) { | 750 } else { |
738 value = number_reduction.replacement(); | 751 value = effect = graph()->NewNode(javascript()->ToNumber(), value, |
739 } else { | 752 context, effect, control); |
740 Node* context = NodeProperties::GetContextInput(node); | |
741 value = graph()->NewNode(javascript()->ToNumber(), value, context, | |
742 effect, control); | |
743 effect = value; | |
744 } | |
745 } | 753 } |
746 // For integer-typed arrays, convert to the integer type. | |
747 if (access.type->Is(Type::Signed32()) && | |
748 !value_type->Is(Type::Signed32())) { | |
749 value = graph()->NewNode(simplified()->NumberToInt32(), value); | |
750 } else if (access.type->Is(Type::Unsigned32()) && | |
751 !value_type->Is(Type::Unsigned32())) { | |
752 value = graph()->NewNode(simplified()->NumberToUint32(), value); | |
753 } | |
754 | |
755 Node* store = | |
756 graph()->NewNode(simplified()->StoreElement(access), pointer, key, | |
757 length, value, effect, control); | |
758 return ReplaceEagerly(node, store); | |
759 } | 754 } |
| 755 // For integer-typed arrays, convert to the integer type. |
| 756 if (TypeOf(access.machine_type()) == kTypeInt32 && |
| 757 !value_type->Is(Type::Signed32())) { |
| 758 value = graph()->NewNode(simplified()->NumberToInt32(), value); |
| 759 } else if (TypeOf(access.machine_type()) == kTypeUint32 && |
| 760 !value_type->Is(Type::Unsigned32())) { |
| 761 value = graph()->NewNode(simplified()->NumberToUint32(), value); |
| 762 } |
| 763 // Check if we can avoid the bounds check. |
| 764 if (key_type->Min() >= 0 && key_type->Max() < array->length()->Number()) { |
| 765 node->set_op(simplified()->StoreElement( |
| 766 AccessBuilder::ForTypedArrayElement(array->type(), true))); |
| 767 node->ReplaceInput(0, buffer); |
| 768 DCHECK_EQ(key, node->InputAt(1)); |
| 769 node->ReplaceInput(2, value); |
| 770 node->ReplaceInput(3, effect); |
| 771 node->ReplaceInput(4, control); |
| 772 node->TrimInputCount(5); |
| 773 return Changed(node); |
| 774 } |
| 775 // Compute byte offset. |
| 776 Node* offset = Word32Shl(key, static_cast<int>(k)); |
| 777 // Turn into a StoreBuffer operation. |
| 778 node->set_op(simplified()->StoreBuffer(access)); |
| 779 node->ReplaceInput(0, buffer); |
| 780 node->ReplaceInput(1, offset); |
| 781 node->ReplaceInput(2, length); |
| 782 node->ReplaceInput(3, value); |
| 783 node->ReplaceInput(4, effect); |
| 784 DCHECK_EQ(control, node->InputAt(5)); |
| 785 DCHECK_EQ(6, node->InputCount()); |
| 786 return Changed(node); |
760 } | 787 } |
761 } | 788 } |
762 return NoChange(); | 789 return NoChange(); |
763 } | 790 } |
764 | 791 |
765 | 792 |
766 static Reduction ReplaceWithReduction(Node* node, Reduction reduction) { | 793 static Reduction ReplaceWithReduction(Node* node, Reduction reduction) { |
767 if (reduction.Changed()) { | 794 if (reduction.Changed()) { |
768 NodeProperties::ReplaceWithValue(node, reduction.replacement()); | 795 NodeProperties::ReplaceWithValue(node, reduction.replacement()); |
769 return reduction; | 796 return reduction; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
850 case IrOpcode::kJSStoreProperty: | 877 case IrOpcode::kJSStoreProperty: |
851 return ReduceJSStoreProperty(node); | 878 return ReduceJSStoreProperty(node); |
852 case IrOpcode::kJSCallFunction: | 879 case IrOpcode::kJSCallFunction: |
853 return JSBuiltinReducer(jsgraph()).Reduce(node); | 880 return JSBuiltinReducer(jsgraph()).Reduce(node); |
854 default: | 881 default: |
855 break; | 882 break; |
856 } | 883 } |
857 return NoChange(); | 884 return NoChange(); |
858 } | 885 } |
859 | 886 |
| 887 |
| 888 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { |
| 889 if (rhs == 0) return lhs; |
| 890 return graph()->NewNode(machine()->Word32Shl(), lhs, |
| 891 jsgraph()->Int32Constant(rhs)); |
| 892 } |
| 893 |
860 } // namespace compiler | 894 } // namespace compiler |
861 } // namespace internal | 895 } // namespace internal |
862 } // namespace v8 | 896 } // namespace v8 |
OLD | NEW |