Commit 7816413f authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[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/677603Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48131}
parent dc3bbbdb
...@@ -1255,24 +1255,34 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess( ...@@ -1255,24 +1255,34 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node); Node* control = NodeProperties::GetControlInput(node);
// Optimize access for constant {receiver}. // Optimize the case where we load from a constant {receiver}.
if (access_mode == AccessMode::kLoad) {
HeapObjectMatcher mreceiver(receiver); HeapObjectMatcher mreceiver(receiver);
if (mreceiver.HasValue() && mreceiver.Value()->IsString()) { if (mreceiver.HasValue() &&
Handle<String> string = Handle<String>::cast(mreceiver.Value()); !mreceiver.Value()->IsNullOrUndefined(isolate())) {
// Check whether we're accessing a known element on the {receiver}
// Strings are immutable in JavaScript. // that is non-configurable, non-writable (i.e. the {receiver} was
if (access_mode == AccessMode::kStore) return NoChange(); // frozen using Object.freeze).
// Properly deal with constant {index}.
NumberMatcher mindex(index); NumberMatcher mindex(index);
if (mindex.IsInteger() && mindex.IsInRange(0.0, string->length() - 1)) { if (mindex.IsInteger() && mindex.IsInRange(0.0, kMaxUInt32)) {
// Constant-fold the {index} access to {string}. LookupIterator it(isolate(), mreceiver.Value(),
Node* value = jsgraph()->HeapConstant( static_cast<uint32_t>(mindex.Value()),
factory()->LookupSingleCharacterStringFromCode( LookupIterator::OWN);
string->Get(static_cast<int>(mindex.Value())))); 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); ReplaceWithValue(node, value, effect, control);
return Replace(value); return Replace(value);
} }
}
// 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());
// We can only assume that the {index} is a valid array index if the IC // 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 // is in element access mode and not MEGAMORPHIC, otherwise there's no
...@@ -1283,13 +1293,16 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess( ...@@ -1283,13 +1293,16 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
index = effect = graph()->NewNode(simplified()->CheckBounds(), index, index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
length, effect, control); length, effect, control);
// Return the character from the {receiver} as single character string. // Return the character from the {receiver} as single character
value = graph()->NewNode(simplified()->StringCharAt(), receiver, index, // string.
control); value = graph()->NewNode(simplified()->StringCharAt(), receiver,
index, control);
ReplaceWithValue(node, value, effect, control); ReplaceWithValue(node, value, effect, control);
return Replace(value); return Replace(value);
} }
} }
}
}
// Check if the {nexus} reports type feedback for the IC. // Check if the {nexus} reports type feedback for the IC.
if (nexus.IsUninitialized()) { if (nexus.IsUninitialized()) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment