| Index: src/compiler/js-native-context-specialization.cc
|
| diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc
|
| index c122634cbb5e82038f7ce6f81a1ae3dc9dc1feea..44521793a035676f137d366a43428e652b1e9c54 100644
|
| --- a/src/compiler/js-native-context-specialization.cc
|
| +++ b/src/compiler/js-native-context-specialization.cc
|
| @@ -427,7 +427,10 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
| if (!(flags() & kDeoptimizationEnabled)) return NoChange();
|
|
|
| // TODO(bmeurer): Add support for non-standard stores.
|
| - if (store_mode != STANDARD_STORE) return NoChange();
|
| + if (store_mode != STANDARD_STORE &&
|
| + store_mode != STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
|
| + return NoChange();
|
| + }
|
|
|
| // Retrieve the native context from the given {node}.
|
| Handle<Context> native_context;
|
| @@ -482,9 +485,9 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
| BuildCheckMaps(receiver, effect, control, access_info.receiver_maps());
|
|
|
| // Access the actual element.
|
| - ValueEffectControl continuation =
|
| - BuildElementAccess(receiver, index, value, effect, control,
|
| - native_context, access_info, access_mode);
|
| + ValueEffectControl continuation = BuildElementAccess(
|
| + receiver, index, value, effect, control, native_context, access_info,
|
| + access_mode, store_mode);
|
| value = continuation.value();
|
| effect = continuation.effect();
|
| control = continuation.control();
|
| @@ -589,7 +592,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
| // Access the actual element.
|
| ValueEffectControl continuation = BuildElementAccess(
|
| this_receiver, this_index, this_value, this_effect, this_control,
|
| - native_context, access_info, access_mode);
|
| + native_context, access_info, access_mode, store_mode);
|
| values.push_back(continuation.value());
|
| effects.push_back(continuation.effect());
|
| controls.push_back(continuation.control());
|
| @@ -952,7 +955,7 @@ JSNativeContextSpecialization::ValueEffectControl
|
| JSNativeContextSpecialization::BuildElementAccess(
|
| Node* receiver, Node* index, Node* value, Node* effect, Node* control,
|
| Handle<Context> native_context, ElementAccessInfo const& access_info,
|
| - AccessMode access_mode) {
|
| + AccessMode access_mode, KeyedAccessStoreMode store_mode) {
|
| // Determine actual holder and perform prototype chain checks.
|
| Handle<JSObject> holder;
|
| if (access_info.holder().ToHandle(&holder)) {
|
| @@ -1002,9 +1005,19 @@ JSNativeContextSpecialization::BuildElementAccess(
|
| common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
|
| check, length, jsgraph()->ZeroConstant());
|
|
|
| - // Check that the {index} is in the valid range for the {receiver}.
|
| - index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
|
| - length, effect, control);
|
| + if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
|
| + // Check that the {index} is a valid array index, we do the actual
|
| + // bounds check below and just skip the store below if it's out of
|
| + // bounds for the {receiver}.
|
| + index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
|
| + jsgraph()->Constant(Smi::kMaxValue),
|
| + effect, control);
|
| + } else {
|
| + // Check that the {index} is in the valid range for the {receiver}.
|
| + DCHECK_EQ(STANDARD_STORE, store_mode);
|
| + index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
|
| + length, effect, control);
|
| + }
|
|
|
| // Load the base and external pointer for the {receiver}.
|
| Node* base_pointer = effect = graph()->NewNode(
|
| @@ -1030,13 +1043,46 @@ JSNativeContextSpecialization::BuildElementAccess(
|
| // Ensure that the {value} is actually a Number.
|
| value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
|
| effect, control);
|
| - effect = graph()->NewNode(
|
| - simplified()->StoreTypedElement(external_array_type), buffer,
|
| - base_pointer, external_pointer, index, value, effect, control);
|
| +
|
| + // Check if we can skip the out-of-bounds store.
|
| + if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
|
| + Node* check =
|
| + graph()->NewNode(simplified()->NumberLessThan(), index, length);
|
| + Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
|
| + check, control);
|
| +
|
| + Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
| + Node* etrue = effect;
|
| + {
|
| + // Perform the actual store.
|
| + etrue = graph()->NewNode(
|
| + simplified()->StoreTypedElement(external_array_type), buffer,
|
| + base_pointer, external_pointer, index, value, etrue, if_true);
|
| + }
|
| +
|
| + Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
| + Node* efalse = effect;
|
| + {
|
| + // Just ignore the out-of-bounds write.
|
| + }
|
| +
|
| + control = graph()->NewNode(common()->Merge(2), if_true, if_false);
|
| + effect =
|
| + graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
|
| + } else {
|
| + // Perform the actual store
|
| + DCHECK_EQ(STANDARD_STORE, store_mode);
|
| + effect = graph()->NewNode(
|
| + simplified()->StoreTypedElement(external_array_type), buffer,
|
| + base_pointer, external_pointer, index, value, effect, control);
|
| + }
|
| break;
|
| }
|
| }
|
| } else {
|
| + // TODO(turbofan): Add support for additional store modes.
|
| + DCHECK_EQ(STANDARD_STORE, store_mode);
|
| +
|
| // Load the length of the {receiver}.
|
| Node* length = effect =
|
| HasOnlyJSArrayMaps(receiver_maps)
|
| @@ -1066,8 +1112,6 @@ JSNativeContextSpecialization::BuildElementAccess(
|
| kFullWriteBarrier};
|
|
|
| // Access the actual element.
|
| - // TODO(bmeurer): Refactor this into separate methods or even a separate
|
| - // class that deals with the elements access.
|
| if (access_mode == AccessMode::kLoad) {
|
| // Compute the real element access type, which includes the hole in case
|
| // of holey backing stores.
|
|
|