v8/test/mjsunit/compiler/array-slice-clone.js
Shu-yu Guo e8ad04c8d8 Reland "[regexp] Ship RegExp match indices"
This reverts commit 8b6fd1471b.

This adds --no-stress-flush-bytecode to the failing assertOptimized test as the flag changed the GC pattern and was deoptimizing code.

Original change's description:
> Revert "[regexp] Ship RegExp match indices"
>
> This reverts commit 72464122bd.
>
> Reason for revert:
> https://ci.chromium.org/p/v8/builders/ci/V8%20Linux%20-%20gc%20stress/32046
>
> Original change's description:
> > [regexp] Ship RegExp match indices
> >
> > I2S:
> > https://groups.google.com/a/chromium.org/g/blink-dev/c/RR_dw_ZXtT0/m/xtgu5jjyAQAJ
> >
> > Bug: v8:9548
> > Change-Id: I8ccf2f4c38f9b9204ae47162303f21d2d44498e8
> > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2682508
> > Commit-Queue: Jakob Gruber <jgruber@chromium.org>
> > Auto-Submit: Shu-yu Guo <syg@chromium.org>
> > Reviewed-by: Jakob Gruber <jgruber@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#72571}
>
> TBR=jgruber@chromium.org,syg@chromium.org
>
> Change-Id: I1173389082928aa5c9895ca4fb360c7ab8ec073b
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: v8:9548
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2681943
> Reviewed-by: Michael Achenbach <machenbach@chromium.org>
> Commit-Queue: Michael Achenbach <machenbach@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#72576}

TBR=machenbach@chromium.org,jgruber@chromium.org,syg@chromium.org

# Not skipping CQ checks because this is a reland.

Bug: v8:9548
Change-Id: Ie18b16f347061602f35e3dea371c03d2ae136127
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2686098
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72613}
2021-02-10 00:36:15 +00:00

483 lines
10 KiB
JavaScript

// 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 --opt --no-stress-flush-bytecode
// Test CloneFastJSArray inserted by JSCallReducer for Array.prototype.slice.
// CloneFastJSArray produces COW arrays if the original array is COW.
// Trigger JSCallReducer on slice() and slice(0)
(function() {
const arr = [1,2,3,4,5];
function slice() {
return arr.slice();
}
function slice0() {
return arr.slice(0);
}
%PrepareFunctionForOptimization(slice0);
%PrepareFunctionForOptimization(slice);
assertEquals(arr, slice());
assertFalse(arr === slice());
assertEquals(slice(), slice0());
assertEquals(slice0(), slice());
%OptimizeFunctionOnNextCall(slice0);
assertEquals(slice(), slice0());
%OptimizeFunctionOnNextCall(slice);
assertEquals(slice(), slice0());
assertOptimized(slice); assertOptimized(slice0);
})();
// This will cause deopt of slice by a CheckMap installed by
// JSNativeContextSpecialization::ReduceNamedAccess
(function() {
const arr = [1,2,3,4,5];
function slice() {
return arr.slice();
}
%PrepareFunctionForOptimization(slice);
assertEquals(arr, slice());
assertEquals(slice(), arr);
%OptimizeFunctionOnNextCall(slice);
slice();
// Trigger deopt here
arr.push(7.2);
assertEquals(slice()[5], 7.2);
})();
// There should not be a deopt cycle.
(function() {
const arr = [1,2,3,4,5];
function slice() {
return arr.slice();
}
%PrepareFunctionForOptimization(slice);
assertEquals(arr, slice());
assertEquals(slice(), arr);
%OptimizeFunctionOnNextCall(slice);
// Trigger opt
assertEquals(slice(), arr);
// Trigger deopt by CheckMap from JSNativeContextSpecialization
arr.push(7.2);
slice();
%PrepareFunctionForOptimization(slice);
%OptimizeFunctionOnNextCall(slice);
// Trigger opt again
slice();
// Should not deopt again
arr.push(8.2);
slice();
assertOptimized(slice);
})();
// JSCallReducer will not reduce because the species has been modified
(function() {
const array = [3,4,5];
function slice(){
return array.slice();
}
class MyArray extends Array {};
array.constructor = MyArray;
%PrepareFunctionForOptimization(slice);
slice(); slice();
%OptimizeFunctionOnNextCall(slice);
var narr = slice();
assertInstanceof(narr, MyArray);
})();
(function() {
const array = [3,4,5];
function slice(){
return array.slice();
}
%PrepareFunctionForOptimization(slice);
slice(); slice();
%OptimizeFunctionOnNextCall(slice);
slice();
class MyArray extends Array {};
array.constructor = MyArray;
// deopt
var narr = slice();
// if not deopt, narr will be instanceof Array
assertTrue(narr instanceof MyArray);
})();
// JSCallReducer adds check for UnreliableReceiverMaps
(function() {
const arr = [1,2,3,4,5];
function slice() {
return arr.slice();
}
%PrepareFunctionForOptimization(slice);
slice(); slice();
arr.foo = 6.2;
%OptimizeFunctionOnNextCall(slice);
// JSCallReducer will add check for UnreliableReceiverMaps
slice();
// Trigger deopt because of DependOnStableMaps
// installed by JSNativeContextSpecialization,
// but not the check installed by ReduceArrayPrototypeSlice itself
arr.bar = 7.2;
let narr = slice();
assertEquals(arr, narr);
assertEquals(narr.foo, undefined);
assertEquals(narr.bar, undefined);
})();
// Multiple maps
(function() {
const iarr = [1,2,3];
const darr = [2.1, 3.3, 0.2];
function slice(arr) {
return arr.slice();
}
%PrepareFunctionForOptimization(slice);
slice(iarr); slice(darr);
slice(iarr); slice(darr);
%OptimizeFunctionOnNextCall(slice);
// The optimization works for both maps
assertEquals(iarr, slice(iarr));
assertEquals(darr, slice(darr));
assertOptimized(slice);
})();
// Tests for the branch of CanInlineArrayIteratingBuiltin
// JSCallReducer will not reduce to CloneFastJSArray
// if array's prototype is not JS_ARRAY_TYPE
(function () {
class MyArray extends Array {
constructor() {
super();
this[6]= 6;
}
}
let array = new MyArray(3, 5, 4);
function slice() {
return array.slice();
}
%PrepareFunctionForOptimization(slice);
assertEquals(slice(),array);
slice();
%OptimizeFunctionOnNextCall(slice);
let narr = slice();
// here, slice supposes to call MyArray's constructor.
// If we optimize with CloneFastJSArray, Array's constructor is called instead.
assertEquals(narr[6], 6);
assertTrue(narr instanceof MyArray);
})();
// JSCallReducer will not reduce to CloneFastJSArray
// if array's instance type is not JS_ARRAY_TYPE.
// CloneFastJSArray does not work with non JS_ARRAY_TYPE.
// Check : receiver_map->instance_type() == JS_ARRAY_TYPE
(function () {
var x = {"0" : 0, "2": 2} ;
x.__proto__ = Array.prototype;
function slice() {
return x.slice();
}
%PrepareFunctionForOptimization(slice);
slice(); slice();
%OptimizeFunctionOnNextCall(slice);
assertEquals(slice(), []);
})();
// JSCallReducer will not reduce to CloneFastJSArray
// since array is not Fast Elements Kind
// Check : IsFastElementsKind(receiver_map->elements_kind())
(function () {
var array = [3, 4, 5];
function slice() {
return array.slice();
}
%PrepareFunctionForOptimization(slice);
assertEquals(slice(),array);
slice();
// a sparse array switches to Dictionary Elements
array[9999] = 0;
%OptimizeFunctionOnNextCall(slice);
var narr = slice();
assertEquals(narr, array);
})();
(function () {
var array = [3, 4, 5];
function slice() {
return array.slice();
}
%PrepareFunctionForOptimization(slice);
assertEquals(slice(),array);
slice();
%OptimizeFunctionOnNextCall(slice);
slice();
// a sparse array switches to Dictionary Elements
array[9999] = 0;
// trigger deopt because map changes
assertEquals(slice(),array);
})();
// JSCallReducer will not reduce to CloneFastJSArray
// if array is used as a prototype and has unstable map
(function () {
var array = [3, 5, 4];
function slice(arr) {
return arr.slice();
}
%PrepareFunctionForOptimization(slice);
// make array's map is_prototype_map()
var x = {__proto__ : array};
assertEquals(slice(array),array);
slice(array);
// make array's map unstable
array.push(6.3);
slice(array);
%OptimizeFunctionOnNextCall(slice);
assertEquals(slice(array),array);
})();
// JSCallReducer will not reduce to CloneFastJSArray
// if the Array prototype got some elements.
// Check: isolate->IsNoElementsProtectorIntact()
(function () {
var array = [, 6, 6];
function slice() {
return array.slice();
}
%PrepareFunctionForOptimization(slice);
assertEquals(slice(),array);
slice();
array.__proto__.push(6);
%OptimizeFunctionOnNextCall(slice);
// if we optimized, we would get [ , 6, 6]
// here, slice copies elements from both the object and the prototype
let narr = slice();
assertNotEquals(Object.getOwnPropertyDescriptor(narr,0), undefined);
assertEquals(narr, [6, 6, 6]);
})();
(function () {
var array = [, 6, 6];
function slice() {
return array.slice();
}
%PrepareFunctionForOptimization(slice);
assertEquals(slice(),array);
slice();
%OptimizeFunctionOnNextCall(slice);
slice();
// Deopt
array.__proto__.push(6);
let narr = slice();
assertNotEquals(Object.getOwnPropertyDescriptor(narr, 0), undefined);
assertEquals(narr[0], 6);
})();
// JSCallReducer will not reduce to CloneFastJSArray
// if the Array prototype is not original
// Check: isolate->IsAnyInitialArrayPrototype(receiver_prototype)
(function () {
var array = [6, , 6];
function slice() {
return array.slice();
}
%PrepareFunctionForOptimization(slice);
assertEquals(slice(),array);
slice();
// change the prototype
array.__proto__ = [ , 6, ];
%OptimizeFunctionOnNextCall(slice);
let narr = slice();
// if optimized, we would get [6, , 6]
assertNotEquals(Object.getOwnPropertyDescriptor(narr, 1), undefined);
assertEquals(narr, [6,6,6]);
})();
(function () {
var array = [6, ,6];
function slice() {
return array.slice();
}
%PrepareFunctionForOptimization(slice);
assertEquals(slice(),array);
slice();
%OptimizeFunctionOnNextCall(slice);
slice();
// change the prototype
array.__proto__ = [,6,];
// deopt because of map changed
let narr = slice();
// if optimized, we would get [6, , 6]
assertNotEquals(Object.getOwnPropertyDescriptor(narr, 1), undefined);
assertEquals(narr, [6,6,6]);
})();
// Packed
// Trigger JSCallReducer on slice() and slice(0)
(function() {
// Non-extensible:
var arr = Object.preventExtensions([1,2,'a',4,5]);
function slice() {
return arr.slice();
}
function slice0() {
return arr.slice(0);
}
function test() {
%PrepareFunctionForOptimization(slice0);
%PrepareFunctionForOptimization(slice);
assertEquals(arr, slice());
assertFalse(arr === slice());
assertEquals(slice(), slice0());
assertEquals(slice0(), slice());
%OptimizeFunctionOnNextCall(slice0);
assertEquals(slice(), slice0());
%OptimizeFunctionOnNextCall(slice);
assertEquals(slice(), slice0());
assertOptimized(slice); assertOptimized(slice0);
}
test();
// Sealed
arr = Object.seal([1,2,'a',4,5]);
test();
// Frozen
arr = Object.freeze([1,2,'a',4,5]);
test();
})();
// Holey
// Trigger JSCallReducer on slice() and slice(0)
(function() {
// Non-extensible:
var arr = Object.preventExtensions([,1,2,'a',4,5]);
function slice() {
return arr.slice();
}
function slice0() {
return arr.slice(0);
}
function test() {
%PrepareFunctionForOptimization(slice0);
%PrepareFunctionForOptimization(slice);
assertEquals(arr, slice());
assertFalse(arr === slice());
assertEquals(slice(), slice0());
assertEquals(slice0(), slice());
%OptimizeFunctionOnNextCall(slice0);
assertEquals(slice(), slice0());
%OptimizeFunctionOnNextCall(slice);
assertEquals(slice(), slice0());
assertOptimized(slice0);
assertOptimized(slice);
}
test();
// Sealed
arr = Object.seal([,1,2,'a',4,5]);
test();
// Frozen
arr = Object.freeze([,1,2,'a',4,5]);
test();
})();