Commit 745ae2d8 authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[turbofan] Constant-fold loads from known copy-on-write arrays.

When accessing elements of a global (constant) JSArray, whose backing
store is copy-on-write, we can just constant-fold the value and insert
a check that the backing store stays the same.

Bug: v8:6816, v8:6815
Change-Id: I090bcec7b1ce72a1f9ed8625680ed91e8c67f27f
Reviewed-on: https://chromium-review.googlesource.com/662757Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47963}
parent 150fd592
...@@ -2169,6 +2169,43 @@ JSNativeContextSpecialization::BuildElementAccess( ...@@ -2169,6 +2169,43 @@ JSNativeContextSpecialization::BuildElementAccess(
simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver, simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
effect, control); effect, control);
// Check if the {receiver} is a known constant with a copy-on-write
// backing store, and whether {index} is within the appropriate
// bounds. In that case we can constant-fold the access and only
// check that the {elements} didn't change. This is sufficient as
// the backing store of a copy-on-write JSArray is defensively copied
// whenever the length or the elements (might) change.
if (access_mode == AccessMode::kLoad) {
HeapObjectMatcher mreceiver(receiver);
if (mreceiver.HasValue() && mreceiver.Value()->IsJSArray()) {
Handle<JSArray> array = Handle<JSArray>::cast(mreceiver.Value());
if (std::find_if(receiver_maps.begin(), receiver_maps.end(),
[array](Handle<Map> map) {
return *map == array->map();
}) != receiver_maps.end()) {
uint32_t length;
if (array->length()->ToUint32(&length) &&
array->elements()->IsCowArray()) {
NumberMatcher mindex(index);
if (mindex.IsInteger() && mindex.IsInRange(0, length - 1)) {
Handle<FixedArray> array_elements(
FixedArray::cast(array->elements()), isolate());
Handle<Object> array_element(
array_elements->get(static_cast<int>(mindex.Value())),
isolate());
Node* check =
graph()->NewNode(simplified()->ReferenceEqual(), elements,
jsgraph()->HeapConstant(array_elements));
effect = graph()->NewNode(simplified()->CheckIf(), check, effect,
control);
Node* value = jsgraph()->Constant(array_element);
return ValueEffectControl(value, effect, control);
}
}
}
}
}
// Don't try to store to a copy-on-write backing store. // Don't try to store to a copy-on-write backing store.
if (access_mode == AccessMode::kStore && if (access_mode == AccessMode::kStore &&
IsSmiOrObjectElementsKind(elements_kind) && IsSmiOrObjectElementsKind(elements_kind) &&
......
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --no-always-opt --opt
// Check that we properly deoptimize TurboFan'ed code when we constant-fold
// elements from a COW array and we change the length of the array.
(function() {
const a = [1, 2, 3];
const foo = () => a[0];
assertEquals(1, foo());
assertEquals(1, foo());
%OptimizeFunctionOnNextCall(foo);
assertEquals(1, foo());
assertOptimized(foo);
a.length = 1;
assertEquals(1, foo());
assertUnoptimized(foo);
})();
// Check that we properly deoptimize TurboFan'ed code when we constant-fold
// elements from a COW array and we change the element of the array.
(function() {
const a = [1, 2, 3];
const foo = () => a[0];
assertEquals(1, foo());
assertEquals(1, foo());
%OptimizeFunctionOnNextCall(foo);
assertEquals(1, foo());
assertOptimized(foo);
a[0] = 42;
assertEquals(42, foo());
assertUnoptimized(foo);
})();
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