Commit 0eb64190 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

Revert "[ic] Improve performance of KeyedStoreIC on literal-based arrays."

This reverts commit 181ac2b0.

Reason for revert: TF changes break load elimination.

Original change's description:
> [ic] Improve performance of KeyedStoreIC on literal-based arrays.
> 
> In mode STORE_AND_GROW_NO_TRANSITION, the handler for elements stores
> used to bail out when seeing a COW array, even if the store that
> installed the handler had been operating on the very same array.
> 
> This CL adds support for COW arrays to the mode (and renames it to
> STORE_AND_GROW_NO_TRANSITION_HANDLE_COW).
> 
> Bug: v8:7334
> Change-Id: I6a15e8c1ff8d4ad4d5b8fc447745dce5d146c67c
> Reviewed-on: https://chromium-review.googlesource.com/876014
> Commit-Queue: Georg Neis <neis@chromium.org>
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#50840}

TBR=neis@chromium.org,ishell@chromium.org,bmeurer@chromium.org

Change-Id: Id841d91b12d199045e0a9c4ddae2c2ead20b5e21
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7334
Reviewed-on: https://chromium-review.googlesource.com/885814Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50860}
parent 4943f4f6
...@@ -7794,14 +7794,14 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, ...@@ -7794,14 +7794,14 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
KeyedAccessStoreMode store_mode, KeyedAccessStoreMode store_mode,
Label* bailout) { Label* bailout) {
CSA_ASSERT(this, Word32BinaryNot(IsJSProxy(object))); CSA_ASSERT(this, Word32BinaryNot(IsJSProxy(object)));
Node* elements = LoadElements(object); Node* elements = LoadElements(object);
if (!IsSmiOrObjectElementsKind(elements_kind)) { if (IsSmiOrObjectElementsKind(elements_kind) &&
CSA_ASSERT(this, Word32BinaryNot(IsFixedCOWArrayMap(LoadMap(elements)))); store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
} else if (!IsCOWHandlingStoreMode(store_mode)) { // Bailout in case of COW elements.
GotoIf(IsFixedCOWArrayMap(LoadMap(elements)), bailout); GotoIf(WordNotEqual(LoadMap(elements),
LoadRoot(Heap::kFixedArrayMapRootIndex)),
bailout);
} }
// TODO(ishell): introduce TryToIntPtrOrSmi() and use OptimalParameterMode(). // TODO(ishell): introduce TryToIntPtrOrSmi() and use OptimalParameterMode().
ParameterMode parameter_mode = INTPTR_PARAMETERS; ParameterMode parameter_mode = INTPTR_PARAMETERS;
key = TryToIntptr(key, bailout); key = TryToIntptr(key, bailout);
...@@ -7867,30 +7867,25 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, ...@@ -7867,30 +7867,25 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
} }
if (IsGrowStoreMode(store_mode)) { if (IsGrowStoreMode(store_mode)) {
elements = elements = CheckForCapacityGrow(object, elements, elements_kind, length,
CheckForCapacityGrow(object, elements, elements_kind, store_mode, key, parameter_mode, is_jsarray, bailout);
length, key, parameter_mode, is_jsarray, bailout);
} else { } else {
GotoIfNot(UintPtrLessThan(key, length), bailout); GotoIfNot(UintPtrLessThan(key, length), bailout);
}
// If we didn't grow {elements}, it might still be COW, in which case we if ((store_mode == STORE_NO_TRANSITION_HANDLE_COW) &&
// copy it now. IsSmiOrObjectElementsKind(elements_kind)) {
if (!IsSmiOrObjectElementsKind(elements_kind)) { elements = CopyElementsOnWrite(object, elements, elements_kind, length,
CSA_ASSERT(this, Word32BinaryNot(IsFixedCOWArrayMap(LoadMap(elements)))); parameter_mode, bailout);
} else if (IsCOWHandlingStoreMode(store_mode)) { }
elements = CopyElementsOnWrite(object, elements, elements_kind, length,
parameter_mode, bailout);
} }
CSA_ASSERT(this, Word32BinaryNot(IsFixedCOWArrayMap(LoadMap(elements))));
StoreElement(elements, elements_kind, key, value, parameter_mode); StoreElement(elements, elements_kind, key, value, parameter_mode);
} }
Node* CodeStubAssembler::CheckForCapacityGrow( Node* CodeStubAssembler::CheckForCapacityGrow(Node* object, Node* elements,
Node* object, Node* elements, ElementsKind kind, ElementsKind kind, Node* length,
KeyedAccessStoreMode store_mode, Node* length, Node* key, Node* key, ParameterMode mode,
ParameterMode mode, bool is_js_array, Label* bailout) { bool is_js_array,
Label* bailout) {
VARIABLE(checked_elements, MachineRepresentation::kTagged); VARIABLE(checked_elements, MachineRepresentation::kTagged);
Label grow_case(this), no_grow_case(this), done(this); Label grow_case(this), no_grow_case(this), done(this);
...@@ -7898,7 +7893,6 @@ Node* CodeStubAssembler::CheckForCapacityGrow( ...@@ -7898,7 +7893,6 @@ Node* CodeStubAssembler::CheckForCapacityGrow(
if (IsHoleyOrDictionaryElementsKind(kind)) { if (IsHoleyOrDictionaryElementsKind(kind)) {
condition = UintPtrGreaterThanOrEqual(key, length); condition = UintPtrGreaterThanOrEqual(key, length);
} else { } else {
// We don't support growing here unless the value is being appended.
condition = WordEqual(key, length); condition = WordEqual(key, length);
} }
Branch(condition, &grow_case, &no_grow_case); Branch(condition, &grow_case, &no_grow_case);
...@@ -7907,18 +7901,20 @@ Node* CodeStubAssembler::CheckForCapacityGrow( ...@@ -7907,18 +7901,20 @@ Node* CodeStubAssembler::CheckForCapacityGrow(
{ {
Node* current_capacity = Node* current_capacity =
TaggedToParameter(LoadFixedArrayBaseLength(elements), mode); TaggedToParameter(LoadFixedArrayBaseLength(elements), mode);
checked_elements.Bind(elements); checked_elements.Bind(elements);
Label fits_capacity(this); Label fits_capacity(this);
GotoIf(UintPtrLessThan(key, current_capacity), &fits_capacity); GotoIf(UintPtrLessThan(key, current_capacity), &fits_capacity);
{ {
Node* new_elements = TryGrowElementsCapacity( Node* new_elements = TryGrowElementsCapacity(
object, elements, kind, key, current_capacity, mode, bailout); object, elements, kind, key, current_capacity, mode, bailout);
checked_elements.Bind(new_elements); checked_elements.Bind(new_elements);
Goto(&fits_capacity); Goto(&fits_capacity);
} }
BIND(&fits_capacity); BIND(&fits_capacity);
if (is_js_array) { if (is_js_array) {
Node* new_length = IntPtrAdd(key, IntPtrOrSmiConstant(1, mode)); Node* new_length = IntPtrAdd(key, IntPtrOrSmiConstant(1, mode));
StoreObjectFieldNoWriteBarrier(object, JSArray::kLengthOffset, StoreObjectFieldNoWriteBarrier(object, JSArray::kLengthOffset,
...@@ -7945,12 +7941,15 @@ Node* CodeStubAssembler::CopyElementsOnWrite(Node* object, Node* elements, ...@@ -7945,12 +7941,15 @@ Node* CodeStubAssembler::CopyElementsOnWrite(Node* object, Node* elements,
VARIABLE(new_elements_var, MachineRepresentation::kTagged, elements); VARIABLE(new_elements_var, MachineRepresentation::kTagged, elements);
Label done(this); Label done(this);
GotoIfNot(IsFixedCOWArrayMap(LoadMap(elements)), &done); GotoIfNot(
WordEqual(LoadMap(elements), LoadRoot(Heap::kFixedCOWArrayMapRootIndex)),
&done);
{ {
Node* capacity = Node* capacity =
TaggedToParameter(LoadFixedArrayBaseLength(elements), mode); TaggedToParameter(LoadFixedArrayBaseLength(elements), mode);
Node* new_elements = GrowElementsCapacity(object, elements, kind, kind, Node* new_elements = GrowElementsCapacity(object, elements, kind, kind,
length, capacity, mode, bailout); length, capacity, mode, bailout);
new_elements_var.Bind(new_elements); new_elements_var.Bind(new_elements);
Goto(&done); Goto(&done);
} }
......
...@@ -1725,9 +1725,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -1725,9 +1725,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
KeyedAccessStoreMode store_mode, Label* bailout); KeyedAccessStoreMode store_mode, Label* bailout);
Node* CheckForCapacityGrow(Node* object, Node* elements, ElementsKind kind, Node* CheckForCapacityGrow(Node* object, Node* elements, ElementsKind kind,
KeyedAccessStoreMode store_mode, Node* length, Node* length, Node* key, ParameterMode mode,
Node* key, ParameterMode mode, bool is_js_array, bool is_js_array, Label* bailout);
Label* bailout);
Node* CopyElementsOnWrite(Node* object, Node* elements, ElementsKind kind, Node* CopyElementsOnWrite(Node* object, Node* elements, ElementsKind kind,
Node* length, ParameterMode mode, Label* bailout); Node* length, ParameterMode mode, Label* bailout);
......
...@@ -541,13 +541,12 @@ void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) { ...@@ -541,13 +541,12 @@ void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) {
StoreFastElementStub(isolate, false, HOLEY_ELEMENTS, STANDARD_STORE) StoreFastElementStub(isolate, false, HOLEY_ELEMENTS, STANDARD_STORE)
.GetCode(); .GetCode();
StoreFastElementStub(isolate, false, HOLEY_ELEMENTS, StoreFastElementStub(isolate, false, HOLEY_ELEMENTS,
STORE_AND_GROW_NO_TRANSITION_HANDLE_COW) STORE_AND_GROW_NO_TRANSITION)
.GetCode(); .GetCode();
for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) { for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) {
ElementsKind kind = static_cast<ElementsKind>(i); ElementsKind kind = static_cast<ElementsKind>(i);
StoreFastElementStub(isolate, true, kind, STANDARD_STORE).GetCode(); StoreFastElementStub(isolate, true, kind, STANDARD_STORE).GetCode();
StoreFastElementStub(isolate, true, kind, StoreFastElementStub(isolate, true, kind, STORE_AND_GROW_NO_TRANSITION)
STORE_AND_GROW_NO_TRANSITION_HANDLE_COW)
.GetCode(); .GetCode();
} }
} }
......
...@@ -2246,11 +2246,10 @@ JSNativeContextSpecialization::BuildElementAccess( ...@@ -2246,11 +2246,10 @@ JSNativeContextSpecialization::BuildElementAccess(
simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver, simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
effect, control); effect, control);
// Don't try to store to a copy-on-write backing store (unless supported by // Don't try to store to a copy-on-write backing store.
// the store mode).
if (access_mode == AccessMode::kStore && if (access_mode == AccessMode::kStore &&
IsSmiOrObjectElementsKind(elements_kind) && IsSmiOrObjectElementsKind(elements_kind) &&
!IsCOWHandlingStoreMode(store_mode)) { store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
effect = graph()->NewNode( effect = graph()->NewNode(
simplified()->CheckMaps( simplified()->CheckMaps(
CheckMapsFlag::kNone, CheckMapsFlag::kNone,
...@@ -2460,15 +2459,6 @@ JSNativeContextSpecialization::BuildElementAccess( ...@@ -2460,15 +2459,6 @@ JSNativeContextSpecialization::BuildElementAccess(
simplified()->MaybeGrowFastElements(mode, VectorSlotPair()), simplified()->MaybeGrowFastElements(mode, VectorSlotPair()),
receiver, elements, index, elements_length, effect, control); receiver, elements, index, elements_length, effect, control);
// If we didn't grow {elements}, it might still be COW, in which case we
// copy it now.
if (IsSmiOrObjectElementsKind(elements_kind) &&
store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW) {
elements = effect =
graph()->NewNode(simplified()->EnsureWritableFastElements(),
receiver, elements, effect, control);
}
// Also update the "length" property if {receiver} is a JSArray. // Also update the "length" property if {receiver} is a JSArray.
if (receiver_is_jsarray) { if (receiver_is_jsarray) {
Node* check = Node* check =
......
...@@ -58,18 +58,12 @@ const char* GetModifier(KeyedAccessLoadMode mode) { ...@@ -58,18 +58,12 @@ const char* GetModifier(KeyedAccessLoadMode mode) {
} }
const char* GetModifier(KeyedAccessStoreMode mode) { const char* GetModifier(KeyedAccessStoreMode mode) {
switch (mode) { if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
case STORE_NO_TRANSITION_HANDLE_COW: if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
return ".COW"; return ".IGNORE_OOB";
case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
return ".STORE+COW";
case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
return ".IGNORE_OOB";
default:
break;
} }
DCHECK(!IsCOWHandlingStoreMode(mode)); if (IsGrowStoreMode(mode)) return ".GROW";
return IsGrowStoreMode(mode) ? ".GROW" : ""; return "";
} }
} // namespace } // namespace
...@@ -1698,7 +1692,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, ...@@ -1698,7 +1692,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
} }
if (receiver_map.is_identical_to(previous_receiver_map) && if (receiver_map.is_identical_to(previous_receiver_map) &&
old_store_mode == STANDARD_STORE && old_store_mode == STANDARD_STORE &&
(store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW || (store_mode == STORE_AND_GROW_NO_TRANSITION ||
store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
store_mode == STORE_NO_TRANSITION_HANDLE_COW)) { store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
// A "normal" IC that handles stores can switch to a version that can // A "normal" IC that handles stores can switch to a version that can
...@@ -1796,7 +1790,7 @@ Handle<Map> KeyedStoreIC::ComputeTransitionedMap( ...@@ -1796,7 +1790,7 @@ Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
// Fall through // Fall through
case STORE_NO_TRANSITION_HANDLE_COW: case STORE_NO_TRANSITION_HANDLE_COW:
case STANDARD_STORE: case STANDARD_STORE:
case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW: case STORE_AND_GROW_NO_TRANSITION:
return map; return map;
} }
UNREACHABLE(); UNREACHABLE();
...@@ -1805,7 +1799,7 @@ Handle<Map> KeyedStoreIC::ComputeTransitionedMap( ...@@ -1805,7 +1799,7 @@ Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
Handle<Object> KeyedStoreIC::StoreElementHandler( Handle<Object> KeyedStoreIC::StoreElementHandler(
Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) { Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
DCHECK(store_mode == STANDARD_STORE || DCHECK(store_mode == STANDARD_STORE ||
store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW || store_mode == STORE_AND_GROW_NO_TRANSITION ||
store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
store_mode == STORE_NO_TRANSITION_HANDLE_COW); store_mode == STORE_NO_TRANSITION_HANDLE_COW);
DCHECK(!receiver_map->DictionaryElementsInPrototypeChainOnly()); DCHECK(!receiver_map->DictionaryElementsInPrototypeChainOnly());
...@@ -1846,7 +1840,7 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers( ...@@ -1846,7 +1840,7 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers(
MapHandles* receiver_maps, ObjectHandles* handlers, MapHandles* receiver_maps, ObjectHandles* handlers,
KeyedAccessStoreMode store_mode) { KeyedAccessStoreMode store_mode) {
DCHECK(store_mode == STANDARD_STORE || DCHECK(store_mode == STANDARD_STORE ||
store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW || store_mode == STORE_AND_GROW_NO_TRANSITION ||
store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
store_mode == STORE_NO_TRANSITION_HANDLE_COW); store_mode == STORE_NO_TRANSITION_HANDLE_COW);
...@@ -1921,7 +1915,7 @@ static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver, ...@@ -1921,7 +1915,7 @@ static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
return STORE_AND_GROW_TRANSITION_TO_OBJECT; return STORE_AND_GROW_TRANSITION_TO_OBJECT;
} }
} }
return STORE_AND_GROW_NO_TRANSITION_HANDLE_COW; return STORE_AND_GROW_NO_TRANSITION;
} else { } else {
// Handle only in-bounds elements accesses. // Handle only in-bounds elements accesses.
if (receiver->HasSmiElements()) { if (receiver->HasSmiElements()) {
......
...@@ -184,7 +184,7 @@ enum KeyedAccessStoreMode { ...@@ -184,7 +184,7 @@ enum KeyedAccessStoreMode {
STANDARD_STORE, STANDARD_STORE,
STORE_TRANSITION_TO_OBJECT, STORE_TRANSITION_TO_OBJECT,
STORE_TRANSITION_TO_DOUBLE, STORE_TRANSITION_TO_DOUBLE,
STORE_AND_GROW_NO_TRANSITION_HANDLE_COW, STORE_AND_GROW_NO_TRANSITION,
STORE_AND_GROW_TRANSITION_TO_OBJECT, STORE_AND_GROW_TRANSITION_TO_OBJECT,
STORE_AND_GROW_TRANSITION_TO_DOUBLE, STORE_AND_GROW_TRANSITION_TO_DOUBLE,
STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS, STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS,
...@@ -204,25 +204,21 @@ static inline bool IsTransitionStoreMode(KeyedAccessStoreMode store_mode) { ...@@ -204,25 +204,21 @@ static inline bool IsTransitionStoreMode(KeyedAccessStoreMode store_mode) {
store_mode == STORE_AND_GROW_TRANSITION_TO_DOUBLE; store_mode == STORE_AND_GROW_TRANSITION_TO_DOUBLE;
} }
static inline bool IsCOWHandlingStoreMode(KeyedAccessStoreMode store_mode) {
return store_mode == STORE_NO_TRANSITION_HANDLE_COW ||
store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW;
}
static inline KeyedAccessStoreMode GetNonTransitioningStoreMode( static inline KeyedAccessStoreMode GetNonTransitioningStoreMode(
KeyedAccessStoreMode store_mode) { KeyedAccessStoreMode store_mode) {
if (store_mode >= STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { if (store_mode >= STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
return store_mode; return store_mode;
} }
if (store_mode >= STORE_AND_GROW_NO_TRANSITION_HANDLE_COW) { if (store_mode >= STORE_AND_GROW_NO_TRANSITION) {
return STORE_AND_GROW_NO_TRANSITION_HANDLE_COW; return STORE_AND_GROW_NO_TRANSITION;
} }
return STANDARD_STORE; return STANDARD_STORE;
} }
static inline bool IsGrowStoreMode(KeyedAccessStoreMode store_mode) { static inline bool IsGrowStoreMode(KeyedAccessStoreMode store_mode) {
return store_mode >= STORE_AND_GROW_NO_TRANSITION_HANDLE_COW && return store_mode >= STORE_AND_GROW_NO_TRANSITION &&
store_mode <= STORE_AND_GROW_TRANSITION_TO_DOUBLE; store_mode <= STORE_AND_GROW_TRANSITION_TO_DOUBLE;
} }
......
// Copyright 2018 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
function f1() {
const x = [,];
x[1] = 42;
assertEquals([undefined, 42], x);
}
f1();
f1();
%OptimizeFunctionOnNextCall(f1);
f1();
f1();
function f2() {
const x = [0];
for (const y of [1, 2, 3, 4]) {
x[x.length] = y;
}
assertEquals([0, 1, 2, 3, 4], x);
}
f2();
f2();
%OptimizeFunctionOnNextCall(f2);
f2();
f2();
function f3() {
const x = [0];
for (const y of [1.1, {}]) {
x[x.length] = y;
}
assertEquals([0, 1.1, {}], x);
}
f3();
f3();
%OptimizeFunctionOnNextCall(f3);
f3();
f3();
function f4(x) {
x[x.length] = x.length;
}
let x1 = [];
f4(x1);
assertEquals([0], x1);
f4(x1);
assertEquals([0, 1], x1);
%OptimizeFunctionOnNextCall(f4);
f4(x1);
assertEquals([0, 1, 2], x1);
f4(x1);
assertEquals([0, 1, 2, 3], x1);
let x2 = {length: 42};
f4(x2);
assertEquals(42, x2[42]);
f4(x2);
assertEquals(42, x2[42]);
%OptimizeFunctionOnNextCall(f4);
f4(x2);
assertEquals(42, x2[42]);
f4(x2);
assertEquals(42, x2[42]);
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