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

Side by Side Diff: src/compiler/js-native-context-specialization.cc

Issue 2210883002: [turbofan] Add support for "ignore OOB stores" to typed arrays. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 4 months 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-native-context-specialization.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 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-native-context-specialization.h" 5 #include "src/compiler/js-native-context-specialization.h"
6 6
7 #include "src/accessors.h" 7 #include "src/accessors.h"
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/compilation-dependencies.h" 9 #include "src/compilation-dependencies.h"
10 #include "src/compiler/access-builder.h" 10 #include "src/compiler/access-builder.h"
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 node->opcode() == IrOpcode::kJSStoreProperty); 420 node->opcode() == IrOpcode::kJSStoreProperty);
421 Node* receiver = NodeProperties::GetValueInput(node, 0); 421 Node* receiver = NodeProperties::GetValueInput(node, 0);
422 Node* effect = NodeProperties::GetEffectInput(node); 422 Node* effect = NodeProperties::GetEffectInput(node);
423 Node* control = NodeProperties::GetControlInput(node); 423 Node* control = NodeProperties::GetControlInput(node);
424 Node* frame_state = NodeProperties::FindFrameStateBefore(node); 424 Node* frame_state = NodeProperties::FindFrameStateBefore(node);
425 425
426 // Not much we can do if deoptimization support is disabled. 426 // Not much we can do if deoptimization support is disabled.
427 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); 427 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
428 428
429 // TODO(bmeurer): Add support for non-standard stores. 429 // TODO(bmeurer): Add support for non-standard stores.
430 if (store_mode != STANDARD_STORE) return NoChange(); 430 if (store_mode != STANDARD_STORE &&
431 store_mode != STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
432 return NoChange();
433 }
431 434
432 // Retrieve the native context from the given {node}. 435 // Retrieve the native context from the given {node}.
433 Handle<Context> native_context; 436 Handle<Context> native_context;
434 if (!GetNativeContext(node).ToHandle(&native_context)) return NoChange(); 437 if (!GetNativeContext(node).ToHandle(&native_context)) return NoChange();
435 438
436 // Compute element access infos for the receiver maps. 439 // Compute element access infos for the receiver maps.
437 AccessInfoFactory access_info_factory(dependencies(), native_context, 440 AccessInfoFactory access_info_factory(dependencies(), native_context,
438 graph()->zone()); 441 graph()->zone());
439 ZoneVector<ElementAccessInfo> access_infos(zone()); 442 ZoneVector<ElementAccessInfo> access_infos(zone());
440 if (!access_info_factory.ComputeElementAccessInfos(receiver_maps, access_mode, 443 if (!access_info_factory.ComputeElementAccessInfos(receiver_maps, access_mode,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 // don't have the kNoWrite flag on it, even though they are not 478 // don't have the kNoWrite flag on it, even though they are not
476 // observable by JavaScript. 479 // observable by JavaScript.
477 effect = 480 effect =
478 graph()->NewNode(common()->Checkpoint(), frame_state, effect, control); 481 graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
479 482
480 // Perform map check on the {receiver}. 483 // Perform map check on the {receiver}.
481 effect = 484 effect =
482 BuildCheckMaps(receiver, effect, control, access_info.receiver_maps()); 485 BuildCheckMaps(receiver, effect, control, access_info.receiver_maps());
483 486
484 // Access the actual element. 487 // Access the actual element.
485 ValueEffectControl continuation = 488 ValueEffectControl continuation = BuildElementAccess(
486 BuildElementAccess(receiver, index, value, effect, control, 489 receiver, index, value, effect, control, native_context, access_info,
487 native_context, access_info, access_mode); 490 access_mode, store_mode);
488 value = continuation.value(); 491 value = continuation.value();
489 effect = continuation.effect(); 492 effect = continuation.effect();
490 control = continuation.control(); 493 control = continuation.control();
491 } else { 494 } else {
492 // The final states for every polymorphic branch. We join them with 495 // The final states for every polymorphic branch. We join them with
493 // Merge+Phi+EffectPhi at the bottom. 496 // Merge+Phi+EffectPhi at the bottom.
494 ZoneVector<Node*> values(zone()); 497 ZoneVector<Node*> values(zone());
495 ZoneVector<Node*> effects(zone()); 498 ZoneVector<Node*> effects(zone());
496 ZoneVector<Node*> controls(zone()); 499 ZoneVector<Node*> controls(zone());
497 500
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
582 // could allow callbacks on elements in the prototype chain that are 585 // could allow callbacks on elements in the prototype chain that are
583 // not compatible with (monomorphic) keyed stores. 586 // not compatible with (monomorphic) keyed stores.
584 Handle<JSObject> holder; 587 Handle<JSObject> holder;
585 if (access_info.holder().ToHandle(&holder)) { 588 if (access_info.holder().ToHandle(&holder)) {
586 AssumePrototypesStable(receiver_maps, native_context, holder); 589 AssumePrototypesStable(receiver_maps, native_context, holder);
587 } 590 }
588 591
589 // Access the actual element. 592 // Access the actual element.
590 ValueEffectControl continuation = BuildElementAccess( 593 ValueEffectControl continuation = BuildElementAccess(
591 this_receiver, this_index, this_value, this_effect, this_control, 594 this_receiver, this_index, this_value, this_effect, this_control,
592 native_context, access_info, access_mode); 595 native_context, access_info, access_mode, store_mode);
593 values.push_back(continuation.value()); 596 values.push_back(continuation.value());
594 effects.push_back(continuation.effect()); 597 effects.push_back(continuation.effect());
595 controls.push_back(continuation.control()); 598 controls.push_back(continuation.control());
596 } 599 }
597 600
598 DCHECK_NULL(fallthrough_control); 601 DCHECK_NULL(fallthrough_control);
599 602
600 // Generate the final merge point for all (polymorphic) branches. 603 // Generate the final merge point for all (polymorphic) branches.
601 int const control_count = static_cast<int>(controls.size()); 604 int const control_count = static_cast<int>(controls.size());
602 if (control_count == 0) { 605 if (control_count == 0) {
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after
945 UNREACHABLE(); 948 UNREACHABLE();
946 return kExternalInt8Array; 949 return kExternalInt8Array;
947 } 950 }
948 951
949 } // namespace 952 } // namespace
950 953
951 JSNativeContextSpecialization::ValueEffectControl 954 JSNativeContextSpecialization::ValueEffectControl
952 JSNativeContextSpecialization::BuildElementAccess( 955 JSNativeContextSpecialization::BuildElementAccess(
953 Node* receiver, Node* index, Node* value, Node* effect, Node* control, 956 Node* receiver, Node* index, Node* value, Node* effect, Node* control,
954 Handle<Context> native_context, ElementAccessInfo const& access_info, 957 Handle<Context> native_context, ElementAccessInfo const& access_info,
955 AccessMode access_mode) { 958 AccessMode access_mode, KeyedAccessStoreMode store_mode) {
956 // Determine actual holder and perform prototype chain checks. 959 // Determine actual holder and perform prototype chain checks.
957 Handle<JSObject> holder; 960 Handle<JSObject> holder;
958 if (access_info.holder().ToHandle(&holder)) { 961 if (access_info.holder().ToHandle(&holder)) {
959 AssumePrototypesStable(access_info.receiver_maps(), native_context, holder); 962 AssumePrototypesStable(access_info.receiver_maps(), native_context, holder);
960 } 963 }
961 964
962 // TODO(bmeurer): We currently specialize based on elements kind. We should 965 // TODO(bmeurer): We currently specialize based on elements kind. We should
963 // also be able to properly support strings and other JSObjects here. 966 // also be able to properly support strings and other JSObjects here.
964 ElementsKind elements_kind = access_info.elements_kind(); 967 ElementsKind elements_kind = access_info.elements_kind();
965 MapList const& receiver_maps = access_info.receiver_maps(); 968 MapList const& receiver_maps = access_info.receiver_maps();
(...skipping 29 matching lines...) Expand all
995 graph()->NewNode( 998 graph()->NewNode(
996 simplified()->NumberBitwiseAnd(), buffer_bitfield, 999 simplified()->NumberBitwiseAnd(), buffer_bitfield,
997 jsgraph()->Constant(JSArrayBuffer::WasNeutered::kMask)), 1000 jsgraph()->Constant(JSArrayBuffer::WasNeutered::kMask)),
998 jsgraph()->ZeroConstant()); 1001 jsgraph()->ZeroConstant());
999 1002
1000 // Default to zero if the {receiver}s buffer was neutered. 1003 // Default to zero if the {receiver}s buffer was neutered.
1001 length = graph()->NewNode( 1004 length = graph()->NewNode(
1002 common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue), 1005 common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
1003 check, length, jsgraph()->ZeroConstant()); 1006 check, length, jsgraph()->ZeroConstant());
1004 1007
1005 // Check that the {index} is in the valid range for the {receiver}. 1008 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
1006 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, 1009 // Check that the {index} is a valid array index, we do the actual
1007 length, effect, control); 1010 // bounds check below and just skip the store below if it's out of
1011 // bounds for the {receiver}.
1012 index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
1013 jsgraph()->Constant(Smi::kMaxValue),
1014 effect, control);
1015 } else {
1016 // Check that the {index} is in the valid range for the {receiver}.
1017 DCHECK_EQ(STANDARD_STORE, store_mode);
1018 index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
1019 length, effect, control);
1020 }
1008 1021
1009 // Load the base and external pointer for the {receiver}. 1022 // Load the base and external pointer for the {receiver}.
1010 Node* base_pointer = effect = graph()->NewNode( 1023 Node* base_pointer = effect = graph()->NewNode(
1011 simplified()->LoadField( 1024 simplified()->LoadField(
1012 AccessBuilder::ForFixedTypedArrayBaseBasePointer()), 1025 AccessBuilder::ForFixedTypedArrayBaseBasePointer()),
1013 elements, effect, control); 1026 elements, effect, control);
1014 Node* external_pointer = effect = graph()->NewNode( 1027 Node* external_pointer = effect = graph()->NewNode(
1015 simplified()->LoadField( 1028 simplified()->LoadField(
1016 AccessBuilder::ForFixedTypedArrayBaseExternalPointer()), 1029 AccessBuilder::ForFixedTypedArrayBaseExternalPointer()),
1017 elements, effect, control); 1030 elements, effect, control);
1018 1031
1019 // Access the actual element. 1032 // Access the actual element.
1020 ExternalArrayType external_array_type = 1033 ExternalArrayType external_array_type =
1021 GetArrayTypeFromElementsKind(elements_kind); 1034 GetArrayTypeFromElementsKind(elements_kind);
1022 switch (access_mode) { 1035 switch (access_mode) {
1023 case AccessMode::kLoad: { 1036 case AccessMode::kLoad: {
1024 value = effect = graph()->NewNode( 1037 value = effect = graph()->NewNode(
1025 simplified()->LoadTypedElement(external_array_type), buffer, 1038 simplified()->LoadTypedElement(external_array_type), buffer,
1026 base_pointer, external_pointer, index, effect, control); 1039 base_pointer, external_pointer, index, effect, control);
1027 break; 1040 break;
1028 } 1041 }
1029 case AccessMode::kStore: { 1042 case AccessMode::kStore: {
1030 // Ensure that the {value} is actually a Number. 1043 // Ensure that the {value} is actually a Number.
1031 value = effect = graph()->NewNode(simplified()->CheckNumber(), value, 1044 value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
1032 effect, control); 1045 effect, control);
1033 effect = graph()->NewNode( 1046
1034 simplified()->StoreTypedElement(external_array_type), buffer, 1047 // Check if we can skip the out-of-bounds store.
1035 base_pointer, external_pointer, index, value, effect, control); 1048 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
1049 Node* check =
1050 graph()->NewNode(simplified()->NumberLessThan(), index, length);
1051 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1052 check, control);
1053
1054 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1055 Node* etrue = effect;
1056 {
1057 // Perform the actual store.
1058 etrue = graph()->NewNode(
1059 simplified()->StoreTypedElement(external_array_type), buffer,
1060 base_pointer, external_pointer, index, value, etrue, if_true);
1061 }
1062
1063 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1064 Node* efalse = effect;
1065 {
1066 // Just ignore the out-of-bounds write.
1067 }
1068
1069 control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1070 effect =
1071 graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1072 } else {
1073 // Perform the actual store
1074 DCHECK_EQ(STANDARD_STORE, store_mode);
1075 effect = graph()->NewNode(
1076 simplified()->StoreTypedElement(external_array_type), buffer,
1077 base_pointer, external_pointer, index, value, effect, control);
1078 }
1036 break; 1079 break;
1037 } 1080 }
1038 } 1081 }
1039 } else { 1082 } else {
1083 // TODO(turbofan): Add support for additional store modes.
1084 DCHECK_EQ(STANDARD_STORE, store_mode);
1085
1040 // Load the length of the {receiver}. 1086 // Load the length of the {receiver}.
1041 Node* length = effect = 1087 Node* length = effect =
1042 HasOnlyJSArrayMaps(receiver_maps) 1088 HasOnlyJSArrayMaps(receiver_maps)
1043 ? graph()->NewNode( 1089 ? graph()->NewNode(
1044 simplified()->LoadField( 1090 simplified()->LoadField(
1045 AccessBuilder::ForJSArrayLength(elements_kind)), 1091 AccessBuilder::ForJSArrayLength(elements_kind)),
1046 receiver, effect, control) 1092 receiver, effect, control)
1047 : graph()->NewNode( 1093 : graph()->NewNode(
1048 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), 1094 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
1049 elements, effect, control); 1095 elements, effect, control);
1050 1096
1051 // Check that the {index} is in the valid range for the {receiver}. 1097 // Check that the {index} is in the valid range for the {receiver}.
1052 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, 1098 index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
1053 length, effect, control); 1099 length, effect, control);
1054 1100
1055 // Compute the element access. 1101 // Compute the element access.
1056 Type* element_type = Type::Any(); 1102 Type* element_type = Type::Any();
1057 MachineType element_machine_type = MachineType::AnyTagged(); 1103 MachineType element_machine_type = MachineType::AnyTagged();
1058 if (IsFastDoubleElementsKind(elements_kind)) { 1104 if (IsFastDoubleElementsKind(elements_kind)) {
1059 element_type = Type::Number(); 1105 element_type = Type::Number();
1060 element_machine_type = MachineType::Float64(); 1106 element_machine_type = MachineType::Float64();
1061 } else if (IsFastSmiElementsKind(elements_kind)) { 1107 } else if (IsFastSmiElementsKind(elements_kind)) {
1062 element_type = type_cache_.kSmi; 1108 element_type = type_cache_.kSmi;
1063 } 1109 }
1064 ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize, 1110 ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize,
1065 element_type, element_machine_type, 1111 element_type, element_machine_type,
1066 kFullWriteBarrier}; 1112 kFullWriteBarrier};
1067 1113
1068 // Access the actual element. 1114 // Access the actual element.
1069 // TODO(bmeurer): Refactor this into separate methods or even a separate
1070 // class that deals with the elements access.
1071 if (access_mode == AccessMode::kLoad) { 1115 if (access_mode == AccessMode::kLoad) {
1072 // Compute the real element access type, which includes the hole in case 1116 // Compute the real element access type, which includes the hole in case
1073 // of holey backing stores. 1117 // of holey backing stores.
1074 if (elements_kind == FAST_HOLEY_ELEMENTS || 1118 if (elements_kind == FAST_HOLEY_ELEMENTS ||
1075 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { 1119 elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
1076 element_access.type = Type::Union( 1120 element_access.type = Type::Union(
1077 element_type, 1121 element_type,
1078 Type::Constant(factory()->the_hole_value(), graph()->zone()), 1122 Type::Constant(factory()->the_hole_value(), graph()->zone()),
1079 graph()->zone()); 1123 graph()->zone());
1080 } 1124 }
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
1335 } 1379 }
1336 1380
1337 1381
1338 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { 1382 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
1339 return jsgraph()->simplified(); 1383 return jsgraph()->simplified();
1340 } 1384 }
1341 1385
1342 } // namespace compiler 1386 } // namespace compiler
1343 } // namespace internal 1387 } // namespace internal
1344 } // namespace v8 1388 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-native-context-specialization.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698