| 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" // TODO(bmeurer): get rid of this? |
| 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 645 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 665 } | 666 } |
| 666 return NoChange(); | 667 return NoChange(); |
| 667 } | 668 } |
| 668 | 669 |
| 669 | 670 |
| 670 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { | 671 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { |
| 671 Node* key = NodeProperties::GetValueInput(node, 1); | 672 Node* key = NodeProperties::GetValueInput(node, 1); |
| 672 Node* base = NodeProperties::GetValueInput(node, 0); | 673 Node* base = NodeProperties::GetValueInput(node, 0); |
| 673 Type* key_type = NodeProperties::GetBounds(key).upper; | 674 Type* key_type = NodeProperties::GetBounds(key).upper; |
| 674 Type* base_type = NodeProperties::GetBounds(base).upper; | 675 Type* base_type = NodeProperties::GetBounds(base).upper; |
| 675 // TODO(mstarzinger): This lowering is not correct if: | |
| 676 // a) The typed array or it's buffer is neutered. | |
| 677 if (base_type->IsConstant() && key_type->Is(Type::Integral32()) && | 676 if (base_type->IsConstant() && key_type->Is(Type::Integral32()) && |
| 678 base_type->AsConstant()->Value()->IsJSTypedArray()) { | 677 base_type->AsConstant()->Value()->IsJSTypedArray()) { |
| 679 // JSLoadProperty(typed-array, int32) | 678 // JSLoadProperty(typed-array, int32) |
| 680 Handle<JSTypedArray> array = | 679 Handle<JSTypedArray> array = |
| 681 Handle<JSTypedArray>::cast(base_type->AsConstant()->Value()); | 680 Handle<JSTypedArray>::cast(base_type->AsConstant()->Value()); |
| 682 if (IsExternalArrayElementsKind(array->map()->elements_kind())) { | 681 if (IsExternalArrayElementsKind(array->map()->elements_kind())) { |
| 683 ExternalArrayType type = array->type(); | 682 Handle<JSArrayBuffer> buffer = |
| 684 double byte_length = array->byte_length()->Number(); | 683 Handle<JSArrayBuffer>::cast(handle(array->buffer(), isolate())); |
| 685 if (byte_length <= kMaxInt) { | 684 size_t byte_length; |
| 686 Handle<ExternalArray> elements = | 685 size_t const page_size = base::OS::CommitPageSize(); |
| 687 Handle<ExternalArray>::cast(handle(array->elements())); | 686 size_t const guard_size = buffer->is_guarded() ? page_size : 0; |
| 687 if (array->byte_offset()->SameValue(Smi::FromInt(0)) && |
| 688 array->byte_length()->SameValue(buffer->byte_length()) && |
| 689 TryNumberToSize(isolate(), array->byte_length(), &byte_length) && |
| 690 byte_length <= 0x80000000u - guard_size) { |
| 691 DCHECK((byte_length % array->element_size()) == 0); |
| 692 BufferAccess const access(array->type(), guard_size); |
| 688 Node* pointer = jsgraph()->IntPtrConstant( | 693 Node* pointer = jsgraph()->IntPtrConstant( |
| 689 bit_cast<intptr_t>(elements->external_pointer())); | 694 bit_cast<intptr_t>(buffer->backing_store())); |
| 690 Node* length = jsgraph()->Constant(array->length()->Number()); | 695 Node* offset = key; |
| 696 int const element_size_shift = |
| 697 WhichPowerOf2(static_cast<int>(array->element_size())); |
| 698 // TODO(bmeurer) |
| 699 Factory* factory = zone()->isolate()->factory(); |
| 700 Handle<Object> min = factory->NewNumber(0); |
| 701 Handle<Object> max = |
| 702 factory->NewNumber((byte_length - 1) >> element_size_shift); |
| 703 if (key_type->Is(Type::Range(min, max, zone()))) { |
| 704 offset = |
| 705 graph()->NewNode(machine()->Word32Shl(), key, |
| 706 jsgraph()->Uint32Constant(element_size_shift)); |
| 707 } else if (element_size_shift != 0) { |
| 708 if (offset->opcode() != IrOpcode::kWord32Sar) return NoChange(); |
| 709 NumberBinopMatcher moffset(offset); |
| 710 if (!moffset.right().Is(element_size_shift)) return NoChange(); |
| 711 offset = moffset.left().node(); |
| 712 } |
| 713 Node* length = jsgraph()->Constant(static_cast<double>(byte_length)); |
| 691 Node* effect = NodeProperties::GetEffectInput(node); | 714 Node* effect = NodeProperties::GetEffectInput(node); |
| 692 Node* load = graph()->NewNode( | 715 Node* control = NodeProperties::GetControlInput(node); |
| 693 simplified()->LoadElement( | 716 Node* load = graph()->NewNode(simplified()->LoadBuffer(access), pointer, |
| 694 AccessBuilder::ForTypedArrayElement(type, true)), | 717 offset, length, effect, control); |
| 695 pointer, key, length, effect); | |
| 696 return ReplaceEagerly(node, load); | 718 return ReplaceEagerly(node, load); |
| 697 } | 719 } |
| 698 } | 720 } |
| 699 } | 721 } |
| 700 return NoChange(); | 722 return NoChange(); |
| 701 } | 723 } |
| 702 | 724 |
| 703 | 725 |
| 704 Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { | 726 Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { |
| 705 Node* key = NodeProperties::GetValueInput(node, 1); | 727 Node* key = NodeProperties::GetValueInput(node, 1); |
| 706 Node* base = NodeProperties::GetValueInput(node, 0); | 728 Node* base = NodeProperties::GetValueInput(node, 0); |
| 707 Node* value = NodeProperties::GetValueInput(node, 2); | 729 Node* value = NodeProperties::GetValueInput(node, 2); |
| 708 Type* key_type = NodeProperties::GetBounds(key).upper; | 730 Type* key_type = NodeProperties::GetBounds(key).upper; |
| 709 Type* base_type = NodeProperties::GetBounds(base).upper; | 731 Type* base_type = NodeProperties::GetBounds(base).upper; |
| 710 // TODO(mstarzinger): This lowering is not correct if: | 732 Type* value_type = NodeProperties::GetBounds(value).upper; |
| 711 // a) The typed array or its buffer is neutered. | 733 if (base_type->IsConstant() && key_type->Is(Type::Integral32()) && |
| 712 if (key_type->Is(Type::Integral32()) && base_type->IsConstant() && | |
| 713 base_type->AsConstant()->Value()->IsJSTypedArray()) { | 734 base_type->AsConstant()->Value()->IsJSTypedArray()) { |
| 714 // JSStoreProperty(typed-array, int32, value) | 735 // JSStoreProperty(typed-array, int32, value) |
| 715 Handle<JSTypedArray> array = | 736 Handle<JSTypedArray> array = |
| 716 Handle<JSTypedArray>::cast(base_type->AsConstant()->Value()); | 737 Handle<JSTypedArray>::cast(base_type->AsConstant()->Value()); |
| 717 if (IsExternalArrayElementsKind(array->map()->elements_kind())) { | 738 if (IsExternalArrayElementsKind(array->map()->elements_kind())) { |
| 718 ExternalArrayType type = array->type(); | 739 Handle<JSArrayBuffer> buffer = |
| 719 double byte_length = array->byte_length()->Number(); | 740 Handle<JSArrayBuffer>::cast(handle(array->buffer(), isolate())); |
| 720 if (byte_length <= kMaxInt) { | 741 size_t byte_length; |
| 721 Handle<ExternalArray> elements = | 742 size_t const page_size = base::OS::CommitPageSize(); |
| 722 Handle<ExternalArray>::cast(handle(array->elements())); | 743 size_t const guard_size = buffer->is_guarded() ? page_size : 0; |
| 744 if (array->byte_offset()->SameValue(Smi::FromInt(0)) && |
| 745 array->byte_length()->SameValue(buffer->byte_length()) && |
| 746 TryNumberToSize(isolate(), array->byte_length(), &byte_length) && |
| 747 byte_length <= 0x80000000u - guard_size) { |
| 748 DCHECK((byte_length % array->element_size()) == 0); |
| 749 BufferAccess const access(array->type(), guard_size); |
| 723 Node* pointer = jsgraph()->IntPtrConstant( | 750 Node* pointer = jsgraph()->IntPtrConstant( |
| 724 bit_cast<intptr_t>(elements->external_pointer())); | 751 bit_cast<intptr_t>(buffer->backing_store())); |
| 725 Node* length = jsgraph()->Constant(array->length()->Number()); | 752 Node* offset = key; |
| 753 int const element_size_shift = |
| 754 WhichPowerOf2(static_cast<int>(array->element_size())); |
| 755 // TODO(bmeurer) |
| 756 Factory* factory = zone()->isolate()->factory(); |
| 757 Handle<Object> min = factory->NewNumber(0); |
| 758 Handle<Object> max = |
| 759 factory->NewNumber((byte_length - 1) >> element_size_shift); |
| 760 if (key_type->Is(Type::Range(min, max, zone()))) { |
| 761 offset = |
| 762 graph()->NewNode(machine()->Word32Shl(), key, |
| 763 jsgraph()->Uint32Constant(element_size_shift)); |
| 764 } else if (element_size_shift != 0) { |
| 765 if (offset->opcode() != IrOpcode::kWord32Sar) return NoChange(); |
| 766 NumberBinopMatcher moffset(offset); |
| 767 if (!moffset.right().Is(element_size_shift)) return NoChange(); |
| 768 offset = moffset.left().node(); |
| 769 } |
| 770 Node* length = jsgraph()->Constant(static_cast<double>(byte_length)); |
| 726 Node* effect = NodeProperties::GetEffectInput(node); | 771 Node* effect = NodeProperties::GetEffectInput(node); |
| 727 Node* control = NodeProperties::GetControlInput(node); | 772 Node* control = NodeProperties::GetControlInput(node); |
| 728 | 773 |
| 729 ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true); | |
| 730 Type* value_type = NodeProperties::GetBounds(value).upper; | |
| 731 // If the value input does not have the required type, insert the | 774 // If the value input does not have the required type, insert the |
| 732 // appropriate conversion. | 775 // appropriate conversion. |
| 733 | 776 |
| 734 // Convert to a number first. | 777 // Convert to a number first. |
| 735 if (!value_type->Is(Type::Number())) { | 778 if (!value_type->Is(Type::Number())) { |
| 736 Reduction number_reduction = ReduceJSToNumberInput(value); | 779 Reduction number_reduction = ReduceJSToNumberInput(value); |
| 737 if (number_reduction.Changed()) { | 780 if (number_reduction.Changed()) { |
| 738 value = number_reduction.replacement(); | 781 value = number_reduction.replacement(); |
| 739 } else { | 782 } else { |
| 740 Node* context = NodeProperties::GetContextInput(node); | 783 Node* context = NodeProperties::GetContextInput(node); |
| 741 value = graph()->NewNode(javascript()->ToNumber(), value, context, | 784 value = graph()->NewNode(javascript()->ToNumber(), value, context, |
| 742 effect, control); | 785 effect, control); |
| 743 effect = value; | 786 effect = value; |
| 744 } | 787 } |
| 745 } | 788 } |
| 746 // For integer-typed arrays, convert to the integer type. | 789 // For integer-typed arrays, convert to the integer type. |
| 747 if (access.type->Is(Type::Signed32()) && | 790 if (TypeOf(access.machine_type()) == kTypeInt32 && |
| 748 !value_type->Is(Type::Signed32())) { | 791 !value_type->Is(Type::Signed32())) { |
| 749 value = graph()->NewNode(simplified()->NumberToInt32(), value); | 792 value = graph()->NewNode(simplified()->NumberToInt32(), value); |
| 750 } else if (access.type->Is(Type::Unsigned32()) && | 793 } else if (TypeOf(access.machine_type()) == kTypeUint32 && |
| 751 !value_type->Is(Type::Unsigned32())) { | 794 !value_type->Is(Type::Unsigned32())) { |
| 752 value = graph()->NewNode(simplified()->NumberToUint32(), value); | 795 value = graph()->NewNode(simplified()->NumberToUint32(), value); |
| 753 } | 796 } |
| 754 | 797 |
| 755 Node* store = | 798 Node* store = |
| 756 graph()->NewNode(simplified()->StoreElement(access), pointer, key, | 799 graph()->NewNode(simplified()->StoreBuffer(access), pointer, offset, |
| 757 length, value, effect, control); | 800 length, value, effect, control); |
| 758 return ReplaceEagerly(node, store); | 801 return ReplaceEagerly(node, store); |
| 759 } | 802 } |
| 760 } | 803 } |
| 761 } | 804 } |
| 762 return NoChange(); | 805 return NoChange(); |
| 763 } | 806 } |
| 764 | 807 |
| 765 | 808 |
| 766 static Reduction ReplaceWithReduction(Node* node, Reduction reduction) { | 809 static Reduction ReplaceWithReduction(Node* node, Reduction reduction) { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 853 return JSBuiltinReducer(jsgraph()).Reduce(node); | 896 return JSBuiltinReducer(jsgraph()).Reduce(node); |
| 854 default: | 897 default: |
| 855 break; | 898 break; |
| 856 } | 899 } |
| 857 return NoChange(); | 900 return NoChange(); |
| 858 } | 901 } |
| 859 | 902 |
| 860 } // namespace compiler | 903 } // namespace compiler |
| 861 } // namespace internal | 904 } // namespace internal |
| 862 } // namespace v8 | 905 } // namespace v8 |
| OLD | NEW |