Commit 024d3499 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

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

This is a reland of 181ac2b0 that fixes
the issue with 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=bmeurer@chromium.org

Bug: v8:7334, chromium:805768
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: I3d9c1b08583e08d68a1d30242a25e4a2190c8c55
Reviewed-on: https://chromium-review.googlesource.com/886261
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50885}
parent 477004b8
...@@ -7847,14 +7847,14 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, ...@@ -7847,14 +7847,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)) {
store_mode != STORE_NO_TRANSITION_HANDLE_COW) { CSA_ASSERT(this, Word32BinaryNot(IsFixedCOWArrayMap(LoadMap(elements))));
// Bailout in case of COW elements. } else if (!IsCOWHandlingStoreMode(store_mode)) {
GotoIf(WordNotEqual(LoadMap(elements), GotoIf(IsFixedCOWArrayMap(LoadMap(elements)), bailout);
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);
...@@ -7920,25 +7920,30 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, ...@@ -7920,25 +7920,30 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
} }
if (IsGrowStoreMode(store_mode)) { if (IsGrowStoreMode(store_mode)) {
elements = CheckForCapacityGrow(object, elements, elements_kind, length, elements =
key, parameter_mode, is_jsarray, bailout); CheckForCapacityGrow(object, elements, elements_kind, store_mode,
length, key, parameter_mode, is_jsarray, bailout);
} else { } else {
GotoIfNot(UintPtrLessThan(key, length), bailout); GotoIfNot(UintPtrLessThan(key, length), bailout);
}
if ((store_mode == STORE_NO_TRANSITION_HANDLE_COW) && // If we didn't grow {elements}, it might still be COW, in which case we
IsSmiOrObjectElementsKind(elements_kind)) { // copy it now.
elements = CopyElementsOnWrite(object, elements, elements_kind, length, if (!IsSmiOrObjectElementsKind(elements_kind)) {
parameter_mode, bailout); CSA_ASSERT(this, Word32BinaryNot(IsFixedCOWArrayMap(LoadMap(elements))));
} } 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* object, Node* elements, Node* CodeStubAssembler::CheckForCapacityGrow(
ElementsKind kind, Node* length, Node* object, Node* elements, ElementsKind kind,
Node* key, ParameterMode mode, KeyedAccessStoreMode store_mode, Node* length, Node* key,
bool is_js_array, ParameterMode mode, bool is_js_array, Label* bailout) {
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);
...@@ -7946,6 +7951,7 @@ Node* CodeStubAssembler::CheckForCapacityGrow(Node* object, Node* elements, ...@@ -7946,6 +7951,7 @@ Node* CodeStubAssembler::CheckForCapacityGrow(Node* object, Node* elements,
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);
...@@ -7954,20 +7960,18 @@ Node* CodeStubAssembler::CheckForCapacityGrow(Node* object, Node* elements, ...@@ -7954,20 +7960,18 @@ Node* CodeStubAssembler::CheckForCapacityGrow(Node* object, Node* elements,
{ {
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,
...@@ -7994,15 +7998,12 @@ Node* CodeStubAssembler::CopyElementsOnWrite(Node* object, Node* elements, ...@@ -7994,15 +7998,12 @@ 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( GotoIfNot(IsFixedCOWArrayMap(LoadMap(elements)), &done);
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);
} }
......
...@@ -1734,8 +1734,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -1734,8 +1734,9 @@ 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,
Node* length, Node* key, ParameterMode mode, KeyedAccessStoreMode store_mode, Node* length,
bool is_js_array, Label* bailout); Node* key, ParameterMode mode, bool is_js_array,
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,12 +541,13 @@ void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) { ...@@ -541,12 +541,13 @@ 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) STORE_AND_GROW_NO_TRANSITION_HANDLE_COW)
.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, STORE_AND_GROW_NO_TRANSITION) StoreFastElementStub(isolate, true, kind,
STORE_AND_GROW_NO_TRANSITION_HANDLE_COW)
.GetCode(); .GetCode();
} }
} }
......
...@@ -2246,10 +2246,11 @@ JSNativeContextSpecialization::BuildElementAccess( ...@@ -2246,10 +2246,11 @@ 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. // Don't try to store to a copy-on-write backing store (unless supported by
// the store mode).
if (access_mode == AccessMode::kStore && if (access_mode == AccessMode::kStore &&
IsSmiOrObjectElementsKind(elements_kind) && IsSmiOrObjectElementsKind(elements_kind) &&
store_mode != STORE_NO_TRANSITION_HANDLE_COW) { !IsCOWHandlingStoreMode(store_mode)) {
effect = graph()->NewNode( effect = graph()->NewNode(
simplified()->CheckMaps( simplified()->CheckMaps(
CheckMapsFlag::kNone, CheckMapsFlag::kNone,
...@@ -2459,6 +2460,15 @@ JSNativeContextSpecialization::BuildElementAccess( ...@@ -2459,6 +2460,15 @@ 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 =
......
...@@ -821,9 +821,11 @@ Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) { ...@@ -821,9 +821,11 @@ Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) {
state = state->SetMaps( state = state->SetMaps(
node, ZoneHandleSet<Map>(factory()->fixed_double_array_map()), zone()); node, ZoneHandleSet<Map>(factory()->fixed_double_array_map()), zone());
} else { } else {
// We know that the resulting elements have the fixed array map. // We know that the resulting elements have the fixed array map or the COW
state = state->SetMaps( // version thereof (if we didn't grow and it was already COW before).
node, ZoneHandleSet<Map>(factory()->fixed_array_map()), zone()); ZoneHandleSet<Map> fixed_array_maps(factory()->fixed_array_map());
fixed_array_maps.insert(factory()->fixed_cow_array_map(), zone());
state = state->SetMaps(node, fixed_array_maps, zone());
} }
// Kill the previous elements on {object}. // Kill the previous elements on {object}.
state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset),
......
...@@ -58,12 +58,18 @@ const char* GetModifier(KeyedAccessLoadMode mode) { ...@@ -58,12 +58,18 @@ const char* GetModifier(KeyedAccessLoadMode mode) {
} }
const char* GetModifier(KeyedAccessStoreMode mode) { const char* GetModifier(KeyedAccessStoreMode mode) {
if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW"; switch (mode) {
if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { case STORE_NO_TRANSITION_HANDLE_COW:
return ".IGNORE_OOB"; return ".COW";
case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
return ".STORE+COW";
case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
return ".IGNORE_OOB";
default:
break;
} }
if (IsGrowStoreMode(mode)) return ".GROW"; DCHECK(!IsCOWHandlingStoreMode(mode));
return ""; return IsGrowStoreMode(mode) ? ".GROW" : "";
} }
} // namespace } // namespace
...@@ -1692,7 +1698,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, ...@@ -1692,7 +1698,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 || (store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
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
...@@ -1790,7 +1796,7 @@ Handle<Map> KeyedStoreIC::ComputeTransitionedMap( ...@@ -1790,7 +1796,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: case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
return map; return map;
} }
UNREACHABLE(); UNREACHABLE();
...@@ -1799,7 +1805,7 @@ Handle<Map> KeyedStoreIC::ComputeTransitionedMap( ...@@ -1799,7 +1805,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 || store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
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());
...@@ -1840,7 +1846,7 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers( ...@@ -1840,7 +1846,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 || store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
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);
...@@ -1915,7 +1921,7 @@ static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver, ...@@ -1915,7 +1921,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; return STORE_AND_GROW_NO_TRANSITION_HANDLE_COW;
} 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, STORE_AND_GROW_NO_TRANSITION_HANDLE_COW,
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,21 +204,25 @@ static inline bool IsTransitionStoreMode(KeyedAccessStoreMode store_mode) { ...@@ -204,21 +204,25 @@ 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) { if (store_mode >= STORE_AND_GROW_NO_TRANSITION_HANDLE_COW) {
return STORE_AND_GROW_NO_TRANSITION; return STORE_AND_GROW_NO_TRANSITION_HANDLE_COW;
} }
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 && return store_mode >= STORE_AND_GROW_NO_TRANSITION_HANDLE_COW &&
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]);
// 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 foo() {
var a = [''];
print(a[0]);
return a;
}
function bar(a) { a[0] = "bazinga!"; }
for (var i = 0; i < 5; i++) bar([]);
%OptimizeFunctionOnNextCall(bar);
bar(foo());
assertEquals([''], 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