diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc index 5578cd81b0..8691f8811b 100644 --- a/src/compiler/js-native-context-specialization.cc +++ b/src/compiler/js-native-context-specialization.cc @@ -1255,39 +1255,52 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess( Node* effect = NodeProperties::GetEffectInput(node); Node* control = NodeProperties::GetControlInput(node); - // Optimize access for constant {receiver}. - HeapObjectMatcher mreceiver(receiver); - if (mreceiver.HasValue() && mreceiver.Value()->IsString()) { - Handle<String> string = Handle<String>::cast(mreceiver.Value()); + // Optimize the case where we load from a constant {receiver}. + if (access_mode == AccessMode::kLoad) { + HeapObjectMatcher mreceiver(receiver); + if (mreceiver.HasValue() && + !mreceiver.Value()->IsNullOrUndefined(isolate())) { + // Check whether we're accessing a known element on the {receiver} + // that is non-configurable, non-writable (i.e. the {receiver} was + // frozen using Object.freeze). + NumberMatcher mindex(index); + if (mindex.IsInteger() && mindex.IsInRange(0.0, kMaxUInt32)) { + LookupIterator it(isolate(), mreceiver.Value(), + static_cast<uint32_t>(mindex.Value()), + LookupIterator::OWN); + if (it.state() == LookupIterator::DATA && it.IsReadOnly() && + !it.IsConfigurable()) { + // We can safely constant-fold the {index} access to {receiver}, + // since the element is non-configurable, non-writable and thus + // cannot change anymore. + value = jsgraph()->Constant(it.GetDataValue()); + ReplaceWithValue(node, value, effect, control); + return Replace(value); + } + } - // Strings are immutable in JavaScript. - if (access_mode == AccessMode::kStore) return NoChange(); + // For constant Strings we can eagerly strength-reduce the keyed + // accesses using the known length, which doesn't change. + if (mreceiver.Value()->IsString()) { + Handle<String> string = Handle<String>::cast(mreceiver.Value()); - // Properly deal with constant {index}. - NumberMatcher mindex(index); - if (mindex.IsInteger() && mindex.IsInRange(0.0, string->length() - 1)) { - // Constant-fold the {index} access to {string}. - Node* value = jsgraph()->HeapConstant( - factory()->LookupSingleCharacterStringFromCode( - string->Get(static_cast<int>(mindex.Value())))); - ReplaceWithValue(node, value, effect, control); - return Replace(value); - } + // We can only assume that the {index} is a valid array index if the IC + // is in element access mode and not MEGAMORPHIC, otherwise there's no + // guard for the bounds check below. + if (nexus.ic_state() != MEGAMORPHIC && nexus.GetKeyType() == ELEMENT) { + // Ensure that {index} is less than {receiver} length. + Node* length = jsgraph()->Constant(string->length()); + index = effect = graph()->NewNode(simplified()->CheckBounds(), index, + length, effect, control); - // We can only assume that the {index} is a valid array index if the IC - // is in element access mode and not MEGAMORPHIC, otherwise there's no - // guard for the bounds check below. - if (nexus.ic_state() != MEGAMORPHIC && nexus.GetKeyType() == ELEMENT) { - // Ensure that {index} is less than {receiver} length. - Node* length = jsgraph()->Constant(string->length()); - index = effect = graph()->NewNode(simplified()->CheckBounds(), index, - length, effect, control); - - // Return the character from the {receiver} as single character string. - value = graph()->NewNode(simplified()->StringCharAt(), receiver, index, - control); - ReplaceWithValue(node, value, effect, control); - return Replace(value); + // Return the character from the {receiver} as single character + // string. + value = graph()->NewNode(simplified()->StringCharAt(), receiver, + index, control); + ReplaceWithValue(node, value, effect, control); + return Replace(value); + } + } } }