e8ad04c8d8
This reverts commit8b6fd1471b
. 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 commit72464122bd
. > > 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}
483 lines
10 KiB
JavaScript
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();
|
|
})();
|