Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(35)

Side by Side Diff: src/compiler/js-typed-lowering.cc

Issue 763963002: [turbofan] Add checked load/store operators. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Reapply fix. Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | src/compiler/machine-operator.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | src/compiler/machine-operator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698