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,39 +1255,52 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess( ...@@ -1255,39 +1255,52 @@ 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}.
HeapObjectMatcher mreceiver(receiver); if (access_mode == AccessMode::kLoad) {
if (mreceiver.HasValue() && mreceiver.Value()->IsString()) { HeapObjectMatcher mreceiver(receiver);
Handle<String> string = Handle<String>::cast(mreceiver.Value()); if (mreceiver.HasValue() &&
!mreceiver.Value()->IsNullOrUndefined(isolate())) {
// Strings are immutable in JavaScript. // Check whether we're accessing a known element on the {receiver}
if (access_mode == AccessMode::kStore) return NoChange(); // that is non-configurable, non-writable (i.e. the {receiver} was
// frozen using Object.freeze).
// Properly deal with constant {index}. NumberMatcher mindex(index);
NumberMatcher mindex(index); if (mindex.IsInteger() && mindex.IsInRange(0.0, kMaxUInt32)) {
if (mindex.IsInteger() && mindex.IsInRange(0.0, string->length() - 1)) { LookupIterator it(isolate(), mreceiver.Value(),
// Constant-fold the {index} access to {string}. static_cast<uint32_t>(mindex.Value()),
Node* value = jsgraph()->HeapConstant( LookupIterator::OWN);
factory()->LookupSingleCharacterStringFromCode( if (it.state() == LookupIterator::DATA && it.IsReadOnly() &&
string->Get(static_cast<int>(mindex.Value())))); !it.IsConfigurable()) {
ReplaceWithValue(node, value, effect, control); // We can safely constant-fold the {index} access to {receiver},
return Replace(value); // since the element is non-configurable, non-writable and thus
} // cannot change anymore.
value = jsgraph()->Constant(it.GetDataValue());
// We can only assume that the {index} is a valid array index if the IC ReplaceWithValue(node, value, effect, control);
// is in element access mode and not MEGAMORPHIC, otherwise there's no return Replace(value);
// 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. // For constant Strings we can eagerly strength-reduce the keyed
value = graph()->NewNode(simplified()->StringCharAt(), receiver, index, // accesses using the known length, which doesn't change.
control); if (mreceiver.Value()->IsString()) {
ReplaceWithValue(node, value, effect, control); Handle<String> string = Handle<String>::cast(mreceiver.Value());
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);
// 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);
}
}
} }
} }
......
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