| 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 (int k = 0; k < static_cast<int>(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 int 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, static_cast<int>(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, 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 double const byte_length = array->byte_length()->Number(); |
| 718 ExternalArrayType type = array->type(); | 731 BufferAccess const access(array->type()); |
| 719 double byte_length = array->byte_length()->Number(); | 732 int const k = ElementSizeLog2Of(access.machine_type()); |
| 720 if (byte_length <= kMaxInt) { | 733 CHECK_LT(k, static_cast<int>(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, 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 |