[turbofan] Constant-fold keyed loads of sealed properties.

We can constant-fold JSLoadProperty(o, i) when o is a known object (i.e.
TurboFan's context specialization provides a known non-null/-undefined
constant value for it), i is a known array index and o["i"] is an
element on the receiver, that is non-configurable and non-writable (i.e.
o was frozen using Object.freeze earlier, or o is a String object).

This significantly reduces execution time of the tagged templates
micro-benchmarks (ES6 and Babel transpiled), when combined with the
CL https://chromium-review.googlesource.com/c/v8/v8/+/677462, it goes
from

  templateStringTagES5: 4552 ms.
  templateStringTagES6: 14185 ms.
  templateStringTagBabel: 7626 ms.

to

  templateStringTagES5: 4550 ms.
  templateStringTagES6: 616 ms.
  templateStringTagBabel: 589 ms.

so overall a solid 23x improvement on the ES6 benchmark. This is
representative of the six-speed-templatestringtag-es6 benchmark.

Bug: v8:6819, v8:6820, v8:6831
Change-Id: Ia45fbdf92977bfbe7400cfa60bd362b78086dc26
Reviewed-on: https://chromium-review.googlesource.com/677603
Reviewed-by: Yang Guo <yangguo@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48131}
This commit is contained in:
Benedikt Meurer 2017-09-21 22:59:00 +02:00 committed by Commit Bot
parent dc3bbbdbe8
commit 7816413f29

View File

@ -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);
}
}
}
}