[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:
parent
dc3bbbdbe8
commit
7816413f29
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user