Commit fd334b32 authored by Mike Stanton's avatar Mike Stanton Committed by Commit Bot

[builtins] Enable Torque Array.prototype.splice

Before, splice was implemented with a C++ fast path and a
comprehensive JavaScript version.

This impl. is entirely in Torque with a fastpath for SMI,
DOUBLE and OBJECT arrays, and a comprehensive slow path.
The same level of "sparse" array support as given by the
array.js implementation is included.

This reland addresses several issues:

* Removed "sparse" array support from splice.
* Addressed ClusterFuzz issue 876443:
  The test and code that uses the fix is in this CL.
  The fix in isolation can be seen here:
  https://chromium-review.googlesource.com/c/v8/v8/+/1199403
* Removed dead code in elements.cc

BUG=chromium:876443, v8:8131, v8:1956, v8:7221

Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: I2d4a66c24ba1edabeca34e27e6ff8ee6136ed5f1
Reviewed-on: https://chromium-review.googlesource.com/1201783
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55610}
parent 0e460c25
......@@ -883,6 +883,7 @@ torque_files = [
"src/builtins/array-foreach.tq",
"src/builtins/array-lastindexof.tq",
"src/builtins/array-reverse.tq",
"src/builtins/array-splice.tq",
"src/builtins/typed-array.tq",
"src/builtins/data-view.tq",
"test/torque/test-torque.tq",
......
......@@ -1747,13 +1747,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Builtins::kArrayPrototypeSlice, 2, false);
SimpleInstallFunction(isolate_, proto, "sort",
Builtins::kArrayPrototypeSort, 1, false);
if (FLAG_enable_experimental_builtins) {
SimpleInstallFunction(isolate_, proto, "splice",
Builtins::kArraySpliceTorque, 2, false);
} else {
SimpleInstallFunction(isolate_, proto, "splice", Builtins::kArraySplice,
2, false);
}
SimpleInstallFunction(isolate_, proto, "splice", Builtins::kArraySplice, 2,
false);
SimpleInstallFunction(isolate_, proto, "includes", Builtins::kArrayIncludes,
1, false);
SimpleInstallFunction(isolate_, proto, "indexOf", Builtins::kArrayIndexOf,
......
......@@ -152,8 +152,8 @@ module array {
assert(IsFastSmiOrTaggedElementsKind(array.map.elements_kind));
const length: Smi = array.length_fast;
array.elements = ExtractFixedArray(
unsafe_cast<FixedArray>(elements), 0, length, length, kFixedArrays);
array.elements =
ExtractFixedArray(unsafe_cast<FixedArray>(elements), 0, length, length);
}
macro TryFastPackedArrayReverse(receiver: Object) labels Slow {
......
// 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.
module array {
// Given {elements}, we want to create a non-zero length array of type
// FixedArrayType. Most of this behavior is outsourced to ExtractFixedArray(),
// but the special case of wanting to have a FixedDoubleArray when given a
// zero-length input FixedArray is handled here.
macro Extract<FixedArrayType : type>(
elements: FixedArrayBase, first: Smi, count: Smi,
capacity: Smi): FixedArrayType {
return unsafe_cast<FixedArrayType>(
ExtractFixedArray(elements, first, count, capacity));
}
Extract<FixedDoubleArray>(
elements: FixedArrayBase, first: Smi, count: Smi,
capacity: Smi): FixedDoubleArray {
if (elements == kEmptyFixedArray) {
let newArray: FixedDoubleArray =
AllocateZeroedFixedDoubleArray(convert<intptr>(capacity));
return newArray;
}
return unsafe_cast<FixedDoubleArray>(
ExtractFixedArray(elements, first, count, capacity));
}
macro FastSplice<FixedArrayType : type, ElementType : type>(
args: constexpr Arguments, a: JSArray, length: Smi, newLength: Smi,
lengthDelta: Smi, actualStart: Smi, insertCount: Smi,
actualDeleteCount: Smi): void labels Bailout {
let elements: FixedArrayBase = a.elements;
let elementsMap: Map = elements.map;
// If the spliced array is larger then the
// source array, then allocate a new FixedArrayType to hold the result.
let newElements: FixedArrayBase = elements;
if (elementsMap == kCOWMap || lengthDelta > 0) {
newElements =
Extract<FixedArrayType>(elements, 0, actualStart, newLength);
if (elementsMap == kCOWMap) {
newElements.map = elementsMap;
}
a.elements = newElements;
}
// Copy over inserted elements.
let k: Smi = actualStart;
if (insertCount > 0) {
let typedNewElements: FixedArrayType =
unsafe_cast<FixedArrayType>(newElements);
for (let e: Object of args [2: ]) {
// The argument elements were already validated to be an appropriate
// {ElementType} to store in {FixedArrayType}.
typedNewElements[k++] = unsafe_cast<ElementType>(e);
}
}
// Copy over elements after deleted elements.
let count: Smi = length - actualStart - actualDeleteCount;
while (count > 0) {
let typedElements: FixedArrayType = unsafe_cast<FixedArrayType>(elements);
let typedNewElements: FixedArrayType =
unsafe_cast<FixedArrayType>(newElements);
CopyArrayElement(typedElements, typedNewElements, k - lengthDelta, k);
k++;
count--;
}
// Fill rest of spliced FixedArray with the hole, but only if the
// destination FixedArray is the original array's, since otherwise the array
// is pre-filled with holes.
if (elements == newElements) {
let typedNewElements: FixedArrayType =
unsafe_cast<FixedArrayType>(newElements);
let limit: Smi = elements.length;
while (k < limit) {
StoreArrayHole(typedNewElements, k);
k++;
}
}
// Update the array's length after all the FixedArray shuffling is done.
a.length = newLength;
}
macro FastArraySplice(
context: Context, args: constexpr Arguments, o: JSReceiver,
originalLengthNumber: Number, actualStartNumber: Number, insertCount: Smi,
actualDeleteCountNumber: Number): Object
labels Bailout {
let originalLength: Smi = cast<Smi>(originalLengthNumber) otherwise Bailout;
let actualStart: Smi = cast<Smi>(actualStartNumber) otherwise Bailout;
let actualDeleteCount: Smi =
cast<Smi>(actualDeleteCountNumber) otherwise Bailout;
let lengthDelta: Smi = insertCount - actualDeleteCount;
let newLength: Smi = originalLength + lengthDelta;
let a: JSArray = cast<JSArray>(o) otherwise Bailout;
let map: Map = a.map;
if (!IsPrototypeInitialArrayPrototype(context, map)) goto Bailout;
if (IsNoElementsProtectorCellInvalid()) goto Bailout;
if (IsArraySpeciesProtectorCellInvalid()) goto Bailout;
// Fast path only works on fast elements kind and with writable length.
let elementsKind: ElementsKind = EnsureArrayPushable(map) otherwise Bailout;
if (!IsFastElementsKind(elementsKind)) goto Bailout;
let oldElementsKind: ElementsKind = elementsKind;
for (let e: Object of args [2: ]) {
if (IsFastSmiElementsKind(elementsKind)) {
if (TaggedIsNotSmi(e)) {
let heapObject: HeapObject = unsafe_cast<HeapObject>(e);
elementsKind = IsHeapNumber(heapObject) ?
AllowDoubleElements(elementsKind) :
AllowNonNumberElements(elementsKind);
}
} else if (IsDoubleElementsKind(elementsKind)) {
if (!IsNumber(e)) {
elementsKind = AllowNonNumberElements(elementsKind);
}
}
}
if (elementsKind != oldElementsKind) {
let smi_elements_kind: Smi = convert<Smi>(convert<int32>(elementsKind));
TransitionElementsKindWithKind(context, a, smi_elements_kind);
}
// Make sure that the length hasn't been changed by side-effect.
let length: Smi = cast<Smi>(a.length) otherwise Bailout;
if (originalLength != length) goto Bailout;
let deletedResult: JSArray =
ExtractFastJSArray(context, a, actualStart, actualDeleteCount);
if (newLength == 0) {
a.elements = kEmptyFixedArray;
a.length = 0;
return deletedResult;
}
if (IsFastSmiOrTaggedElementsKind(elementsKind)) {
FastSplice<FixedArray, Object>(
args, a, length, newLength, lengthDelta, actualStart, insertCount,
actualDeleteCount) otherwise Bailout;
} else {
FastSplice<FixedDoubleArray, Number>(
args, a, length, newLength, lengthDelta, actualStart, insertCount,
actualDeleteCount) otherwise Bailout;
}
return deletedResult;
}
macro FillDeletedElementsArray(
context: Context, o: JSReceiver, actualStart: Number,
actualDeleteCount: Number, a: JSReceiver): Object {
// 10. Let k be 0.
let k: Number = 0;
// 11. Repeat, while k < actualDeleteCount
while (k < actualDeleteCount) {
// a. Let from be ! ToString(actualStart + k).
let from: Number = actualStart + k;
// b. Let fromPresent be ? HasProperty(O, from).
let fromPresent: Boolean = HasProperty(context, o, from);
// c. If fromPresent is true, then
if (fromPresent == True) {
// i. Let fromValue be ? Get(O, from).
let fromValue: Object = GetProperty(context, o, from);
// ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(k), fromValue).
CreateDataProperty(context, a, k, fromValue);
}
// d. Increment k by 1.
k++;
}
// 12. Perform ? Set(A, "length", actualDeleteCount, true).
SetProperty(context, a, 'length', actualDeleteCount);
return a;
}
// HandleForwardCase implements step 15. "If itemCount < actualDeleteCount,
// then...""
macro HandleForwardCase(
context: Context, o: JSReceiver, len: Number, itemCount: Number,
actualStart: Number, actualDeleteCount: Number): void {
// 15. If itemCount < actualDeleteCount, then
// a. Let k be actualStart.
let k: Number = actualStart;
// b. Repeat, while k < (len - actualDeleteCount)
while (k < (len - actualDeleteCount)) {
// i. Let from be ! ToString(k + actualDeleteCount).
let from: Number = k + actualDeleteCount;
// ii. Let to be ! ToString(k + itemCount).
let to: Number = k + itemCount;
// iii. Let fromPresent be ? HasProperty(O, from).
let fromPresent: Boolean = HasProperty(context, o, from);
// iv. If fromPresent is true, then
if (fromPresent == True) {
// 1. Let fromValue be ? Get(O, from).
let fromValue: Object = GetProperty(context, o, from);
// 2. Perform ? Set(O, to, fromValue, true).
SetProperty(context, o, to, fromValue);
// v. Else fromPresent is false,
} else {
// 1. Perform ? DeletePropertyOrThrow(O, to).
DeleteProperty(context, o, to, kStrict);
}
// vi. Increase k by 1.
k++;
}
// c. Let k be len.
k = len;
// d. Repeat, while k > (len - actualDeleteCount + itemCount)
while (k > (len - actualDeleteCount + itemCount)) {
// i. Perform ? DeletePropertyOrThrow(O, ! ToString(k - 1)).
DeleteProperty(context, o, k - 1, kStrict);
// ii. Decrease k by 1.
k--;
}
}
// HandleBackwardCase implements step 16. "Else if itemCount >
// actualDeleteCount, then..."
macro HandleBackwardCase(
context: Context, o: JSReceiver, len: Number, itemCount: Number,
actualStart: Number, actualDeleteCount: Number): void {
// 16. Else if itemCount > actualDeleteCount, then
// a. Let k be (len - actualDeleteCount).
let k: Number = len - actualDeleteCount;
// b. Repeat, while k > actualStart
while (k > actualStart) {
// i. Let from be ! ToString(k + actualDeleteCount - 1).
let from: Number = k + actualDeleteCount - 1;
// ii. Let to be ! ToString(k + itemCount - 1).
let to: Number = k + itemCount - 1;
// iii. Let fromPresent be ? HasProperty(O, from).
let fromPresent: Boolean = HasProperty(context, o, from);
// iv. If fromPresent is true, then
if (fromPresent == True) {
// 1. Let fromValue be ? Get(O, from).
let fromValue: Object = GetProperty(context, o, from);
// 2. Perform ? Set(O, to, fromValue, true).
SetProperty(context, o, to, fromValue);
// v. Else fromPresent is false,
} else {
// 1. Perform ? DeletePropertyOrThrow(O, to).
DeleteProperty(context, o, to, kStrict);
}
// vi. Decrease k by 1.
k--;
}
}
macro SlowSplice(
context: Context, arguments: constexpr Arguments, o: JSReceiver,
len: Number, actualStart: Number, insertCount: Smi,
actualDeleteCount: Number): Object {
let affected: Number = len - actualStart - actualDeleteCount;
// 9. Let A be ? ArraySpeciesCreate(O, actualDeleteCount).
let a: JSReceiver = ArraySpeciesCreate(context, o, actualDeleteCount);
let itemCount: Number = insertCount;
// Steps 9 through 12: creating the array of deleted elements.
FillDeletedElementsArray(context, o, actualStart, actualDeleteCount, a);
// 13. Let items be a List whose elements are, in left-to-right order,
// the portion of the actual argument list starting with the third
// argument. The list is empty if fewer than three arguments were
// passed.
// 14. Let itemCount be the Number of elements in items.
// (done above).
// 15. If itemCount < actualDeleteCount, then
if (itemCount < actualDeleteCount) {
HandleForwardCase(
context, o, len, itemCount, actualStart, actualDeleteCount);
// 16. Else if itemCount > actualDeleteCount, then
} else if (itemCount > actualDeleteCount) {
HandleBackwardCase(
context, o, len, itemCount, actualStart, actualDeleteCount);
}
// 17. Let k be actualStart.
let k: Number = actualStart;
// 18. Repeat, while items is not empty
// a. Remove the first element from items and let E be the value of that
// element.
if (arguments.length > 2) {
for (let e: Object of arguments [2: ]) {
// b. Perform ? Set(O, ! ToString(k), E, true).
SetProperty(context, o, k, e);
// c. Increase k by 1.
k = k + 1;
}
}
// 19. Perform ? Set(O, "length", len - actualDeleteCount + itemCount,
// true).
SetProperty(context, o, 'length', len - actualDeleteCount + itemCount);
return a;
}
// https://tc39.github.io/ecma262/#sec-array.prototype.splice
javascript builtin ArraySplice(
context: Context, receiver: Object, ...arguments): Object {
// 1. Let O be ? ToObject(this value).
let o: JSReceiver = ToObject(context, receiver);
// 2. Let len be ? ToLength(? Get(O, "length")).
let len: Number = GetLengthProperty(context, o);
// 3. Let relativeStart be ? ToInteger(start).
let start: Object = arguments[0];
let relativeStart: Number = ToInteger_Inline(context, start);
// 4. If relativeStart < 0, let actualStart be max((len + relativeStart),
// 0);
// else let actualStart be min(relativeStart, len).
let actualStart: Number = relativeStart < 0 ?
max((len + relativeStart), 0) :
min(relativeStart, len);
let insertCount: Smi;
let actualDeleteCount: Number;
// 5. If the Number of actual arguments is 0, then
if (arguments.length == 0) {
// a. Let insertCount be 0.
insertCount = 0;
// b. Let actualDeleteCount be 0.
actualDeleteCount = 0;
// 6. Else if the Number of actual arguments is 1, then
} else if (arguments.length == 1) {
// a. Let insertCount be 0.
insertCount = 0;
// b. Let actualDeleteCount be len - actualStart.
actualDeleteCount = len - actualStart;
// 7. Else,
} else {
// a. Let insertCount be the Number of actual arguments minus 2.
insertCount = convert<Smi>(arguments.length) - 2;
// b. Let dc be ? ToInteger(deleteCount).
let deleteCount: Object = arguments[1];
let dc: Number = ToInteger_Inline(context, deleteCount);
// c. Let actualDeleteCount be min(max(dc, 0), len - actualStart).
actualDeleteCount = min(max(dc, 0), len - actualStart);
}
// 8. If len + insertCount - actualDeleteCount > 2^53-1, throw a
// Bailout exception.
let new_length: Number = len + insertCount - actualDeleteCount;
if (new_length > kMaxSafeInteger) {
ThrowTypeError(context, kInvalidArrayLength, start);
}
try {
return FastArraySplice(
context, arguments, o, len, actualStart, insertCount,
actualDeleteCount) otherwise Bailout;
}
label Bailout {}
// If the fast case fails, just continue with the slow, correct,
// spec-compliant case.
return SlowSplice(
context, arguments, o, len, actualStart, insertCount,
actualDeleteCount);
}
}
......@@ -24,293 +24,40 @@ module array {
}
}
macro FastArraySplice(
context: Context, args: constexpr Arguments, o: Object,
originalLengthNumber: Number, actualStartNumber: Number, insertCount: Smi,
actualDeleteCountNumber: Number): Object
labels Bailout {
let originalLength: Smi = cast<Smi>(originalLengthNumber) otherwise Bailout;
let actualStart: Smi = cast<Smi>(actualStartNumber) otherwise Bailout;
let actualDeleteCount: Smi =
cast<Smi>(actualDeleteCountNumber) otherwise Bailout;
let lengthDelta: Smi = insertCount - actualDeleteCount;
let newLength: Smi = originalLength + lengthDelta;
let a: JSArray = cast<JSArray>(o) otherwise Bailout;
let map: Map = a.map;
if (!IsPrototypeInitialArrayPrototype(context, map)) goto Bailout;
if (IsNoElementsProtectorCellInvalid()) goto Bailout;
if (IsArraySpeciesProtectorCellInvalid()) goto Bailout;
// Fast path only works on fast elements kind and with writable length.
let elementsKind: ElementsKind = EnsureArrayPushable(map) otherwise Bailout;
if (!IsFastElementsKind(elementsKind)) goto Bailout;
// For now, only support non-double fast elements
if (!IsFastSmiOrTaggedElementsKind(elementsKind)) goto Bailout;
if (IsFastSmiElementsKind(elementsKind)) {
for (let e: Object of args [2: ]) {
if (TaggedIsNotSmi(e)) goto Bailout;
}
}
// Make sure that the length hasn't been changed by side-effect.
let length: Smi = cast<Smi>(a.length) otherwise Bailout;
if (originalLength != length) goto Bailout;
let deletedResult: JSArray =
ExtractFastJSArray(context, a, actualStart, actualDeleteCount);
if (newLength == 0) {
a.elements = kEmptyFixedArray;
a.length = 0;
return deletedResult;
}
let elements: FixedArray = cast<FixedArray>(a.elements) otherwise Bailout;
let elementsMap: Map = elements.map;
// If the source is a COW array or the spliced array is larger then the
// source array, then allocate a new FixedArray to hold the result.
let newElements: FixedArray = elements;
if ((elementsMap == kCOWMap) || (lengthDelta > 0)) {
newElements = ExtractFixedArray(
elements, 0, actualStart, newLength, kAllFixedArrays);
newElements.map = elementsMap;
a.elements = newElements;
}
// Double check that the array is still in fast elements mode
assert(IsFastSmiElementsKind(a.map.elements_kind));
// Copy over inserted elements.
let k: Smi = actualStart;
if (insertCount > 0) {
for (let e: Object of args [2: ]) {
newElements[k++] = e;
}
}
// Copy over elements after deleted elements.
let count: Smi = length - actualStart - actualDeleteCount;
while (count > 0) {
let e: Object = elements[k - lengthDelta];
newElements[k++] = e;
count--;
macro IsArray(o: Object): bool {
try {
let array: JSArray = cast<JSArray>(o) otherwise NotArray;
return true;
}
// Fill rest of spliced FixedArray with the hole, but only if the
// destination FixedArray is the original array's, since otherwise the array
// is pre-filled with holes.
if (elements == newElements) {
let limit: Smi = elements.length;
while (k < limit) {
newElements[k++] = Hole;
}
label NotArray {
return false;
}
// Update the array's length after all the FixedArray shuffling is done.
a.length = newLength;
return deletedResult;
}
// https://tc39.github.io/ecma262/#sec-array.prototype.splice
javascript builtin ArraySpliceTorque(
context: Context, receiver: Object, ...arguments): Object {
// 1. Let O be ? ToObject(this value).
let o: JSReceiver = ToObject(context, receiver);
// 2. Let len be ? ToLength(? Get(O, "length")).
let len: Number = GetLengthProperty(context, o);
// 3. Let relativeStart be ? ToInteger(start).
let start: Object = arguments[0];
let relativeStart: Number = ToInteger_Inline(context, start);
// 4. If relativeStart < 0, let actualStart be max((len + relativeStart),
// 0);
// else let actualStart be min(relativeStart, len).
let actualStart: Number = relativeStart < 0 ?
max((len + relativeStart), 0) :
min(relativeStart, len);
macro StoreArrayHole(elements: FixedDoubleArray, k: Smi): void {
StoreFixedDoubleArrayHoleSmi(elements, k);
}
let insertCount: Smi;
let actualDeleteCount: Number;
// 5. If the Number of actual arguments is 0, then
if (arguments.length == 0) {
// a. Let insertCount be 0.
insertCount = 0;
// b. Let actualDeleteCount be 0.
actualDeleteCount = 0;
// 6. Else if the Number of actual arguments is 1, then
} else if (arguments.length == 1) {
// a. Let insertCount be 0.
insertCount = 0;
// b. Let actualDeleteCount be len - actualStart.
actualDeleteCount = len - actualStart;
// 7. Else,
} else {
// a. Let insertCount be the Number of actual arguments minus 2.
insertCount = convert<Smi>(arguments.length) - 2;
// b. Let dc be ? ToInteger(deleteCount).
let deleteCount: Object = arguments[1];
let dc: Number = ToInteger_Inline(context, deleteCount);
// c. Let actualDeleteCount be min(max(dc, 0), len - actualStart).
actualDeleteCount = min(max(dc, 0), len - actualStart);
}
macro StoreArrayHole(elements: FixedArray, k: Smi): void {
elements[k] = Hole;
}
// 8. If len + insertCount - actualDeleteCount > 2^53-1, throw a
// Bailout exception.
if (len + insertCount - actualDeleteCount > kMaxSafeInteger) {
ThrowRangeError(context, kInvalidArrayLength);
}
macro CopyArrayElement(
elements: FixedArray, newElements: FixedArray, from: Smi, to: Smi): void {
let e: Object = elements[from];
newElements[to] = e;
}
macro CopyArrayElement(
elements: FixedDoubleArray, newElements: FixedDoubleArray, from: Smi,
to: Smi): void {
try {
return FastArraySplice(
context, arguments, o, len, actualStart, insertCount,
actualDeleteCount) otherwise Bailout;
}
label Bailout {}
// If the fast case fails, just continue with the slow, correct,
// spec-compliant case.
// 9. Let A be ? ArraySpeciesCreate(O, actualDeleteCount).
let a: Object = ArraySpeciesCreate(context, o, actualDeleteCount);
// 10. Let k be 0.
let k: Number = 0;
// 11. Repeat, while k < actualDeleteCount
while (k < actualDeleteCount) {
// a. Let from be ! ToString(actualStart + k).
let from: String = ToString_Inline(context, actualStart + k);
// b. Let fromPresent be ? HasProperty(O, from).
let fromPresent: Oddball = HasProperty(context, o, from);
// c. If fromPresent is true, then
if (fromPresent == True) {
// i. Let fromValue be ? Get(O, from).
let fromValue: Object = GetProperty(context, o, from);
// ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(k), fromValue).
CreateDataProperty(context, a, ToString_Inline(context, k), fromValue);
}
// d. Increment k by 1.
k = k + 1;
}
// 12. Perform ? Set(A, "length", actualDeleteCount, true).
SetProperty(context, a, 'length', actualDeleteCount);
// 13. Let items be a List whose elements are, in left-to-right order,
// the portion of the actual argument list starting with the third
// argument. The list is empty if fewer than three arguments were
// passed.
// 14. Let itemCount be the Number of elements in items.
let itemCount: Number = insertCount;
// 15. If itemCount < actualDeleteCount, then
if (itemCount < actualDeleteCount) {
// a. Let k be actualStart.
let k: Number = actualStart;
// b. Repeat, while k < (len - actualDeleteCount)
while (k < (len - actualDeleteCount)) {
// i. Let from be ! ToString(k + actualDeleteCount).
let from: String = ToString_Inline(context, k + actualDeleteCount);
// ii. Let to be ! ToString(k + itemCount).
let to: String = ToString_Inline(context, k + itemCount);
// iii. Let fromPresent be ? HasProperty(O, from).
let fromPresent: Oddball = HasProperty(context, o, from);
// iv. If fromPresent is true, then
if (fromPresent == True) {
// 1. Let fromValue be ? Get(O, from).
let fromValue: Object = GetProperty(context, o, from);
// 2. Perform ? Set(O, to, fromValue, true).
SetProperty(context, o, to, fromValue);
// v. Else fromPresent is false,
} else {
// 1. Perform ? DeletePropertyOrThrow(O, to).
DeleteProperty(context, o, to, kStrict);
}
// vi. Increase k by 1.
k = k + 1;
}
// c. Let k be len.
k = len;
// d. Repeat, while k > (len - actualDeleteCount + itemCount)
while (k > (len - actualDeleteCount + itemCount)) {
// i. Perform ? DeletePropertyOrThrow(O, ! ToString(k - 1)).
DeleteProperty(context, o, ToString_Inline(context, k - 1), kStrict);
// ii. Decrease k by 1.
k = k - 1;
}
// 16. Else if itemCount > actualDeleteCount, then
} else if (itemCount > actualDeleteCount) {
// a. Let k be (len - actualDeleteCount).
let k: Number = len - actualDeleteCount;
// b. Repeat, while k > actualStart
while (k > actualStart) {
// i. Let from be ! ToString(k + actualDeleteCount - 1).
let from: String = ToString_Inline(context, k + actualDeleteCount - 1);
// ii. Let to be ! ToString(k + itemCount - 1).
let to: String = ToString_Inline(context, k + itemCount - 1);
// iii. Let fromPresent be ? HasProperty(O, from).
let fromPresent: Oddball = HasProperty(context, o, from);
// iv. If fromPresent is true, then
if (fromPresent == True) {
// 1. Let fromValue be ? Get(O, from).
let fromValue: Object = GetProperty(context, o, from);
// 2. Perform ? Set(O, to, fromValue, true).
SetProperty(context, o, to, fromValue);
// v. Else fromPresent is false,
} else {
// 1. Perform ? DeletePropertyOrThrow(O, to).
DeleteProperty(context, o, to, kStrict);
}
// vi. Decrease k by 1.
k = k - 1;
}
let floatValue: float64 = LoadDoubleWithHoleCheck(elements, from)
otherwise FoundHole;
newElements[to] = floatValue;
}
// 17. Let k be actualStart.
k = actualStart;
// 18. Repeat, while items is not empty
// a. Remove the first element from items and let E be the value of that
// element.
if (arguments.length > 2) {
for (let e: Object of arguments [2: ]) {
// b. Perform ? Set(O, ! ToString(k), E, true).
SetProperty(context, o, ToString_Inline(context, k), e);
// c. Increase k by 1.
k = k + 1;
}
label FoundHole {
StoreArrayHole(newElements, to);
}
// 19. Perform ? Set(O, "length", len - actualDeleteCount + itemCount,
// true).
SetProperty(context, o, 'length', len - actualDeleteCount + itemCount);
return a;
}
}
......@@ -107,6 +107,8 @@ type FixedUint8ClampedArray extends FixedTypedArray;
type FixedBigUint64Array extends FixedTypedArray;
type FixedBigInt64Array extends FixedTypedArray;
const kFixedDoubleArrays: constexpr ExtractFixedArrayFlags generates
'ExtractFixedArrayFlag::kFixedDoubleArrays';
const kAllFixedArrays: constexpr ExtractFixedArrayFlags generates
'ExtractFixedArrayFlag::kAllFixedArrays';
const kFixedArrays: constexpr ExtractFixedArrayFlags generates
......@@ -167,9 +169,8 @@ const kSloppy: constexpr LanguageMode generates 'LanguageMode::kSloppy';
const SMI_PARAMETERS: constexpr ParameterMode generates 'SMI_PARAMETERS';
const INTPTR_PARAMETERS: constexpr ParameterMode generates 'INTPTR_PARAMETERS';
const SKIP_WRITE_BARRIER: constexpr WriteBarrierMode
generates 'SKIP_WRITE_BARRIER';
generates 'SKIP_WRITE_BARRIER';
extern macro Is64(): constexpr bool;
......@@ -177,6 +178,7 @@ extern macro SelectBooleanConstant(bool): Boolean;
extern macro Print(constexpr string);
extern macro Print(constexpr string, Object);
extern macro Comment(constexpr string);
extern macro Print(Object);
extern macro DebugBreak();
extern macro ToInteger_Inline(Context, Object): Number;
......@@ -195,7 +197,8 @@ extern macro ThrowTypeError(Context, constexpr MessageTemplate): never;
extern macro ThrowTypeError(Context, constexpr MessageTemplate, Object): never;
extern macro ThrowTypeError(
Context, constexpr MessageTemplate, Object, Object, Object): never;
extern macro ArraySpeciesCreate(Context, Object, Number): Object;
extern macro ArraySpeciesCreate(Context, Object, Number): JSReceiver;
extern macro InternalArrayCreate(Context, Number): JSArray;
extern macro EnsureArrayPushable(Map): ElementsKind labels Bailout;
extern builtin ToObject(Context, Object): JSReceiver;
......@@ -205,7 +208,9 @@ extern macro IsTheHole(Object): bool;
extern macro IsString(HeapObject): bool;
extern builtin ToString(Context, Object): String;
extern runtime CreateDataProperty(Context, Object, Object, Object);
extern runtime NormalizeElements(Context, JSObject);
extern runtime TransitionElementsKindWithKind(Context, JSObject, Smi);
extern runtime CreateDataProperty(Context, JSReceiver, Object, Object);
extern macro LoadRoot(constexpr RootListIndex): Object;
extern macro StoreRoot(constexpr RootListIndex, Object): Object;
......@@ -232,6 +237,10 @@ extern operator '>=' macro SmiGreaterThanOrEqual(Smi, Smi): bool;
extern operator '==' macro ElementsKindEqual(
constexpr ElementsKind, constexpr ElementsKind): constexpr bool;
extern operator '==' macro ElementsKindEqual(ElementsKind, ElementsKind): bool;
operator '!=' macro ElementsKindNotEqual(
k1: ElementsKind, k2: ElementsKind): bool {
return !ElementsKindEqual(k1, k2);
}
extern macro IsFastElementsKind(constexpr ElementsKind): constexpr bool;
extern macro IsDoubleElementsKind(constexpr ElementsKind): constexpr bool;
......@@ -250,11 +259,14 @@ extern operator '>=' macro UintPtrGreaterThanOrEqual(uintptr, uintptr): bool;
extern operator '==' macro Float64Equal(float64, float64): bool;
extern operator '!=' macro Float64NotEqual(float64, float64): bool;
extern operator
'==' macro BranchIfNumberEqual(Number, Number): never labels Taken, NotTaken;
extern operator
'<' macro BranchIfNumberLessThan(Number, Number): never labels Taken, NotTaken;
extern operator
'<=' macro BranchIfNumberLessThanOrEqual(Number, Number): never labels Taken,
NotTaken;
extern operator
'>' macro BranchIfNumberGreaterThan(Number, Number): never labels Taken,
NotTaken;
......@@ -327,8 +339,8 @@ extern operator '.length' macro GetArgumentsLength(constexpr Arguments): intptr;
extern operator
'[]' macro GetArgumentValue(constexpr Arguments, intptr): Object;
extern operator 'is<Smi>' macro TaggedIsSmi(Object): bool;
extern operator 'isnt<Smi>' macro TaggedIsNotSmi(Object): bool;
extern macro TaggedIsSmi(Object): bool;
extern macro TaggedIsNotSmi(Object): bool;
extern macro TaggedIsPositiveSmi(Object): bool;
extern macro HeapObjectToJSDataView(HeapObject): JSDataView labels CastError;
......@@ -336,18 +348,20 @@ extern macro TaggedToHeapObject(Object): HeapObject labels CastError;
extern macro TaggedToSmi(Object): Smi labels CastError;
extern macro HeapObjectToJSArray(HeapObject): JSArray labels CastError;
extern macro HeapObjectToCallable(HeapObject): Callable labels CastError;
extern macro HeapObjectToFixedArray(HeapObject):
FixedArray labels CastError;
extern macro HeapObjectToFixedArray(HeapObject): FixedArray labels CastError;
extern macro HeapObjectToFixedDoubleArray(HeapObject):
FixedDoubleArray labels CastError;
extern macro TaggedToNumber(Object): Number labels CastError;
macro cast_HeapObject<A : type>(o : HeapObject) : A labels CastError;
cast_HeapObject<HeapObject>(o : HeapObject) : HeapObject labels CastError { return o; }
macro cast_HeapObject<A : type>(o: HeapObject): A labels CastError;
cast_HeapObject<HeapObject>(o: HeapObject): HeapObject labels CastError {
return o;
}
cast_HeapObject<FixedArray>(o: HeapObject): FixedArray labels CastError {
return HeapObjectToFixedArray(o) otherwise CastError;
}
cast_HeapObject<FixedDoubleArray>(o: HeapObject): FixedDoubleArray labels CastError {
cast_HeapObject<FixedDoubleArray>(o: HeapObject):
FixedDoubleArray labels CastError {
return HeapObjectToFixedDoubleArray(o) otherwise CastError;
}
cast_HeapObject<JSDataView>(o: HeapObject): JSDataView labels CastError {
......@@ -367,8 +381,8 @@ macro cast<A : type>(o: HeapObject): A labels CastError {
// cast_HeapObject allows this default-implementation to be non-recursive.
// Otherwise the generated CSA code might run into infinite recursion.
macro cast<A : type>(o: Object): A labels CastError {
return cast_HeapObject<A>(
TaggedToHeapObject(o) otherwise CastError) otherwise CastError;
return cast_HeapObject<A>(TaggedToHeapObject(o) otherwise CastError)
otherwise CastError;
}
cast<Smi>(o: Object): Smi labels CastError {
return TaggedToSmi(o) otherwise CastError;
......@@ -474,6 +488,13 @@ from_constexpr<Object>(s: constexpr string): Object {
macro convert<A : type>(i: constexpr int31): A {
return i;
}
extern macro ConvertElementsKindToInt(ElementsKind): int32;
macro convert<A : type>(elements_kind: ElementsKind): A;
convert<int32>(elements_kind: ElementsKind): int32 {
return ConvertElementsKindToInt(elements_kind);
}
macro convert<A : type>(i: int32): A;
convert<Number>(i: int32): Number {
return ChangeInt32ToTagged(i);
......@@ -560,6 +581,9 @@ unsafe_cast<HeapNumber>(n: Number): HeapNumber {
return UnsafeCastNumberToHeapNumber(n);
}
macro unsafe_cast<A : type>(o: Object): A;
unsafe_cast<Object>(o: Object): Object {
return o;
}
unsafe_cast<FixedArray>(o: Object): FixedArray {
return UnsafeCastObjectToFixedArray(o);
}
......@@ -646,13 +670,16 @@ extern operator
extern operator
'[]=' macro StoreFixedArrayElement(FixedArray, intptr, Object): void;
extern operator
'[]=' macro StoreFixedArrayElement(
FixedArray, constexpr int31, Object): void;
'[]=' macro StoreFixedArrayElement(FixedArray, constexpr int31, Object): void;
extern operator
'[]=' macro StoreFixedArrayElementSmi(FixedArray, Smi, Object): void;
operator '[]=' macro StoreFixedDoubleArrayNumber(
a: FixedDoubleArray, index: Smi, value: Number): void {
a[index] = convert<float64>(value);
}
extern macro StoreFixedArrayElementSmi(FixedArray, Smi, Object,
constexpr WriteBarrierMode): void;
extern macro StoreFixedArrayElementSmi(
FixedArray, Smi, Object, constexpr WriteBarrierMode): void;
extern operator '.instance_type' macro LoadMapInstanceType(Map): int32;
......@@ -678,6 +705,28 @@ extern macro IsFastSmiOrTaggedElementsKind(ElementsKind): bool;
extern macro IsFastSmiElementsKind(ElementsKind): bool;
extern macro IsHoleyFastElementsKind(ElementsKind): bool;
macro AllowDoubleElements(kind: ElementsKind): ElementsKind {
if (kind == PACKED_SMI_ELEMENTS) {
return PACKED_DOUBLE_ELEMENTS;
} else if (kind == HOLEY_SMI_ELEMENTS) {
return HOLEY_DOUBLE_ELEMENTS;
}
return kind;
}
macro AllowNonNumberElements(kind: ElementsKind): ElementsKind {
if (kind == PACKED_SMI_ELEMENTS) {
return PACKED_ELEMENTS;
} else if (kind == HOLEY_SMI_ELEMENTS) {
return HOLEY_ELEMENTS;
} else if (kind == PACKED_DOUBLE_ELEMENTS) {
return PACKED_ELEMENTS;
} else if (kind == HOLEY_DOUBLE_ELEMENTS) {
return HOLEY_ELEMENTS;
}
return kind;
}
extern macro AllocateZeroedFixedArray(intptr): FixedArray;
extern macro AllocateZeroedFixedDoubleArray(intptr): FixedDoubleArray;
......@@ -693,8 +742,13 @@ extern macro AllocateJSArray(constexpr ElementsKind, Map, Smi, Smi): JSArray;
extern macro IsElementsKindGreaterThan(
ElementsKind, constexpr ElementsKind): bool;
extern operator
'[]=' macro StoreFixedDoubleArrayElementSmi(
FixedDoubleArray, Smi, float64): void;
extern macro LoadDoubleWithHoleCheck(FixedDoubleArray, Smi): float64
labels IfHole;
extern macro StoreFixedDoubleArrayHoleSmi(FixedDoubleArray, Smi): void;
extern macro Call(Context, Callable, Object): Object;
extern macro Call(Context, Callable, Object, Object): Object;
......@@ -705,8 +759,7 @@ extern macro Call(
extern macro Call(
Context, Callable, Object, Object, Object, Object, Object, Object): Object;
extern macro ExtractFixedArray(
FixedArray, Smi, Smi, Smi, constexpr ExtractFixedArrayFlags): FixedArray;
extern macro ExtractFixedArray(FixedArrayBase, Smi, Smi, Smi): FixedArrayBase;
extern builtin ExtractFastJSArray(Context, JSArray, Smi, Smi): JSArray;
......@@ -741,12 +794,17 @@ labels IfHole {
}
}
extern macro TransitionElementsKind(
JSObject, Map, ElementsKind, ElementsKind): void labels Bailout;
extern macro IsCallable(HeapObject): bool;
extern macro IsJSArray(HeapObject): bool;
extern macro IsJSReceiver(HeapObject): bool;
extern macro TaggedIsCallable(Object): bool;
extern macro IsDetachedBuffer(JSArrayBuffer): bool;
extern macro IsHeapNumber(HeapObject): bool;
extern macro IsFixedArray(HeapObject): bool;
extern macro IsNumber(Object): bool;
extern macro IsExtensibleMap(Map): bool;
extern macro IsCustomElementsReceiverInstanceType(int32): bool;
extern macro IsFastJSArray(Object, Context): bool;
......@@ -758,9 +816,9 @@ macro NumberIsNaN(number: Number): bool {
case (Smi) {
return false;
} case (hn : HeapNumber) {
let value: float64 = convert<float64>(hn);
return value != value;
}
let value: float64 = convert<float64>(hn);
return value != value;
}
}
}
......
......@@ -23,34 +23,6 @@ namespace internal {
namespace {
inline bool ClampedToInteger(Isolate* isolate, Object* object, int* out) {
// This is an extended version of ECMA-262 7.1.11 handling signed values
// Try to convert object to a number and clamp values to [kMinInt, kMaxInt]
if (object->IsSmi()) {
*out = Smi::ToInt(object);
return true;
} else if (object->IsHeapNumber()) {
double value = HeapNumber::cast(object)->value();
if (std::isnan(value)) {
*out = 0;
} else if (value > kMaxInt) {
*out = kMaxInt;
} else if (value < kMinInt) {
*out = kMinInt;
} else {
*out = static_cast<int>(value);
}
return true;
} else if (object->IsNullOrUndefined(isolate)) {
*out = 0;
return true;
} else if (object->IsBoolean()) {
*out = object->IsTrue(isolate);
return true;
}
return false;
}
inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate,
JSArray* receiver) {
return JSObject::PrototypeHasNoElements(isolate, receiver);
......@@ -637,67 +609,6 @@ BUILTIN(ArrayUnshift) {
return Smi::FromInt(new_length);
}
BUILTIN(ArraySplice) {
HandleScope scope(isolate);
Handle<Object> receiver = args.receiver();
if (V8_UNLIKELY(
!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3,
args.length() - 3) ||
// If this is a subclass of Array, then call out to JS.
!Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) ||
// If anything with @@species has been messed with, call out to JS.
!isolate->IsArraySpeciesLookupChainIntact())) {
return CallJsIntrinsic(isolate, isolate->array_splice(), args);
}
Handle<JSArray> array = Handle<JSArray>::cast(receiver);
int argument_count = args.length() - 1;
int relative_start = 0;
if (argument_count > 0) {
DisallowHeapAllocation no_gc;
if (!ClampedToInteger(isolate, args[1], &relative_start)) {
AllowHeapAllocation allow_allocation;
return CallJsIntrinsic(isolate, isolate->array_splice(), args);
}
}
int len = Smi::ToInt(array->length());
// clip relative start to [0, len]
int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
: Min(relative_start, len);
int actual_delete_count;
if (argument_count == 1) {
// SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
// given as a request to delete all the elements from the start.
// And it differs from the case of undefined delete count.
// This does not follow ECMA-262, but we do the same for compatibility.
DCHECK_GE(len - actual_start, 0);
actual_delete_count = len - actual_start;
} else {
int delete_count = 0;
DisallowHeapAllocation no_gc;
if (argument_count > 1) {
if (!ClampedToInteger(isolate, args[2], &delete_count)) {
AllowHeapAllocation allow_allocation;
return CallJsIntrinsic(isolate, isolate->array_splice(), args);
}
}
actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
}
int add_count = (argument_count > 1) ? (argument_count - 2) : 0;
int new_length = len - actual_delete_count + add_count;
if (new_length != len && JSArray::HasReadOnlyLength(array)) {
AllowHeapAllocation allow_allocation;
return CallJsIntrinsic(isolate, isolate->array_splice(), args);
}
ElementsAccessor* accessor = array->GetElementsAccessor();
Handle<JSArray> result_array = accessor->Splice(
array, actual_start, actual_delete_count, &args, add_count);
return *result_array;
}
// Array Concat -------------------------------------------------------------
namespace {
......
......@@ -319,8 +319,6 @@ namespace internal {
TFJ(ArrayPrototypeShift, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-array.prototype.slice */ \
TFJ(ArrayPrototypeSlice, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-array.prototype.splice */ \
CPP(ArraySplice) \
/* ES6 #sec-array.prototype.unshift */ \
CPP(ArrayUnshift) \
/* Support for Array.from and other array-copying idioms */ \
......
......@@ -4246,6 +4246,33 @@ void CodeStubAssembler::FillFixedArrayWithValue(
mode);
}
void CodeStubAssembler::StoreFixedDoubleArrayHole(
TNode<FixedDoubleArray> array, Node* index, ParameterMode parameter_mode) {
CSA_SLOW_ASSERT(this, MatchesParameterMode(index, parameter_mode));
Node* offset =
ElementOffsetFromIndex(index, PACKED_DOUBLE_ELEMENTS, parameter_mode,
FixedArray::kHeaderSize - kHeapObjectTag);
CSA_ASSERT(this, IsOffsetInBounds(
offset, LoadAndUntagFixedArrayBaseLength(array),
FixedDoubleArray::kHeaderSize, PACKED_DOUBLE_ELEMENTS));
Node* double_hole =
Is64() ? ReinterpretCast<UintPtrT>(Int64Constant(kHoleNanInt64))
: ReinterpretCast<UintPtrT>(Int32Constant(kHoleNanLower32));
// TODO(danno): When we have a Float32/Float64 wrapper class that
// preserves double bits during manipulation, remove this code/change
// this to an indexed Float64 store.
if (Is64()) {
StoreNoWriteBarrier(MachineRepresentation::kWord64, array, offset,
double_hole);
} else {
StoreNoWriteBarrier(MachineRepresentation::kWord32, array, offset,
double_hole);
StoreNoWriteBarrier(MachineRepresentation::kWord32, array,
IntPtrAdd(offset, IntPtrConstant(kPointerSize)),
double_hole);
}
}
void CodeStubAssembler::FillFixedArrayWithSmiZero(TNode<FixedArray> array,
TNode<IntPtrT> length) {
CSA_ASSERT(this, WordEqual(length, LoadAndUntagFixedArrayBaseLength(array)));
......@@ -10050,6 +10077,10 @@ void CodeStubAssembler::BranchIfNumberRelationalComparison(
// Both {left} and {right} are Smi, so just perform a fast
// Smi comparison.
switch (op) {
case Operation::kEqual:
BranchIfSmiEqual(smi_left, smi_right, if_true,
if_false);
break;
case Operation::kLessThan:
BranchIfSmiLessThan(smi_left, smi_right, if_true,
if_false);
......@@ -10096,6 +10127,10 @@ void CodeStubAssembler::BranchIfNumberRelationalComparison(
BIND(&do_float_comparison);
{
switch (op) {
case Operation::kEqual:
Branch(Float64Equal(var_left_float.value(), var_right_float.value()),
if_true, if_false);
break;
case Operation::kLessThan:
Branch(Float64LessThan(var_left_float.value(), var_right_float.value()),
if_true, if_false);
......@@ -12001,6 +12036,15 @@ Node* CodeStubAssembler::ArraySpeciesCreate(TNode<Context> context,
len);
}
Node* CodeStubAssembler::InternalArrayCreate(TNode<Context> context,
TNode<Number> len) {
Node* native_context = LoadNativeContext(context);
Node* const constructor = LoadContextElement(
native_context, Context::INTERNAL_ARRAY_FUNCTION_INDEX);
return ConstructJS(CodeFactory::Construct(isolate()), context, constructor,
len);
}
Node* CodeStubAssembler::IsDetachedBuffer(Node* buffer) {
CSA_ASSERT(this, HasInstanceType(buffer, JS_ARRAY_BUFFER_TYPE));
......
......@@ -1210,6 +1210,19 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
TNode<FixedDoubleArray> object, Node* index, TNode<Float64T> value,
ParameterMode parameter_mode = INTPTR_PARAMETERS);
void StoreFixedDoubleArrayElementSmi(TNode<FixedDoubleArray> object,
TNode<Smi> index,
TNode<Float64T> value) {
StoreFixedDoubleArrayElement(object, index, value, SMI_PARAMETERS);
}
void StoreFixedDoubleArrayHole(TNode<FixedDoubleArray> array, Node* index,
ParameterMode mode = INTPTR_PARAMETERS);
void StoreFixedDoubleArrayHoleSmi(TNode<FixedDoubleArray> array,
TNode<Smi> index) {
StoreFixedDoubleArrayHole(array, index, SMI_PARAMETERS);
}
Node* StoreFeedbackVectorSlot(
Node* object, Node* index, Node* value,
WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
......@@ -1445,6 +1458,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* ArraySpeciesCreate(TNode<Context> context, TNode<Object> originalArray,
TNode<Number> len);
Node* InternalArrayCreate(TNode<Context> context, TNode<Number> len);
void FillFixedArrayWithValue(ElementsKind kind, Node* array, Node* from_index,
Node* to_index,
......@@ -1520,6 +1534,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
return UncheckedCast<FixedDoubleArray>(base);
}
TNode<Int32T> ConvertElementsKindToInt(TNode<Int32T> elements_kind) {
return UncheckedCast<Int32T>(elements_kind);
}
enum class ExtractFixedArrayFlag {
kFixedArrays = 1,
kFixedDoubleArrays = 2,
......@@ -1560,12 +1578,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
ExtractFixedArrayFlag::kAllFixedArrays,
ParameterMode parameter_mode = INTPTR_PARAMETERS);
TNode<FixedArrayBase> ExtractFixedArray(
TNode<FixedArrayBase> source, TNode<Smi> first, TNode<Smi> count,
TNode<Smi> capacity,
ExtractFixedArrayFlags extract_flags =
ExtractFixedArrayFlag::kAllFixedArrays) {
return ExtractFixedArray(source, first, count, capacity, extract_flags,
TNode<FixedArrayBase> ExtractFixedArray(TNode<FixedArrayBase> source,
TNode<Smi> first, TNode<Smi> count,
TNode<Smi> capacity) {
return ExtractFixedArray(source, first, count, capacity,
ExtractFixedArrayFlag::kAllFixedArrays,
SMI_PARAMETERS);
}
......@@ -2561,6 +2578,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
ElementsKind to_kind, bool is_jsarray,
Label* bailout);
void TransitionElementsKind(TNode<JSReceiver> object, TNode<Map> map,
ElementsKind from_kind, ElementsKind to_kind,
Label* bailout) {
TransitionElementsKind(object, map, from_kind, to_kind, true, bailout);
}
void TrapAllocationMemento(Node* object, Label* memento_found);
TNode<IntPtrT> PageFromAddress(TNode<IntPtrT> address);
......@@ -2652,26 +2675,32 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
void BranchIfNumberRelationalComparison(Operation op, Node* left, Node* right,
Label* if_true, Label* if_false);
void BranchIfNumberLessThan(Node* left, Node* right, Label* if_true,
Label* if_false) {
void BranchIfNumberEqual(TNode<Number> left, TNode<Number> right,
Label* if_true, Label* if_false) {
BranchIfNumberRelationalComparison(Operation::kEqual, left, right, if_true,
if_false);
}
void BranchIfNumberLessThan(TNode<Number> left, TNode<Number> right,
Label* if_true, Label* if_false) {
BranchIfNumberRelationalComparison(Operation::kLessThan, left, right,
if_true, if_false);
}
void BranchIfNumberLessThanOrEqual(Node* left, Node* right, Label* if_true,
Label* if_false) {
void BranchIfNumberLessThanOrEqual(TNode<Number> left, TNode<Number> right,
Label* if_true, Label* if_false) {
BranchIfNumberRelationalComparison(Operation::kLessThanOrEqual, left, right,
if_true, if_false);
}
void BranchIfNumberGreaterThan(Node* left, Node* right, Label* if_true,
Label* if_false) {
void BranchIfNumberGreaterThan(TNode<Number> left, TNode<Number> right,
Label* if_true, Label* if_false) {
BranchIfNumberRelationalComparison(Operation::kGreaterThan, left, right,
if_true, if_false);
}
void BranchIfNumberGreaterThanOrEqual(Node* left, Node* right, Label* if_true,
Label* if_false) {
void BranchIfNumberGreaterThanOrEqual(TNode<Number> left, TNode<Number> right,
Label* if_true, Label* if_false) {
BranchIfNumberRelationalComparison(Operation::kGreaterThanOrEqual, left,
right, if_true, if_false);
}
......
......@@ -71,46 +71,46 @@ enum ContextLookupFlags {
V(ASYNC_GENERATOR_AWAIT_CAUGHT, JSFunction, async_generator_await_caught) \
V(ASYNC_GENERATOR_AWAIT_UNCAUGHT, JSFunction, async_generator_await_uncaught)
#define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \
V(ARRAY_SPLICE_INDEX, JSFunction, array_splice) \
V(ARRAY_UNSHIFT_INDEX, JSFunction, array_unshift) \
V(ARRAY_ENTRIES_ITERATOR_INDEX, JSFunction, array_entries_iterator) \
V(ARRAY_FOR_EACH_ITERATOR_INDEX, JSFunction, array_for_each_iterator) \
V(ARRAY_KEYS_ITERATOR_INDEX, JSFunction, array_keys_iterator) \
V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) \
V(CANONICALIZE_LOCALE_LIST_FUNCTION_INDEX, JSFunction, \
canonicalize_locale_list) \
V(ERROR_FUNCTION_INDEX, JSFunction, error_function) \
V(ERROR_TO_STRING, JSFunction, error_to_string) \
V(EVAL_ERROR_FUNCTION_INDEX, JSFunction, eval_error_function) \
V(GLOBAL_EVAL_FUN_INDEX, JSFunction, global_eval_fun) \
V(GLOBAL_PROXY_FUNCTION_INDEX, JSFunction, global_proxy_function) \
V(MAP_DELETE_INDEX, JSFunction, map_delete) \
V(MAP_GET_INDEX, JSFunction, map_get) \
V(MAP_HAS_INDEX, JSFunction, map_has) \
V(MAP_SET_INDEX, JSFunction, map_set) \
V(FUNCTION_HAS_INSTANCE_INDEX, JSFunction, function_has_instance) \
V(OBJECT_VALUE_OF, JSFunction, object_value_of) \
V(OBJECT_TO_STRING, JSFunction, object_to_string) \
V(PROMISE_CATCH_INDEX, JSFunction, promise_catch) \
V(PROMISE_FUNCTION_INDEX, JSFunction, promise_function) \
V(RANGE_ERROR_FUNCTION_INDEX, JSFunction, range_error_function) \
V(REFERENCE_ERROR_FUNCTION_INDEX, JSFunction, reference_error_function) \
V(CACHED_OR_NEW_SERVICE_LOCALE_FUNCTION_INDEX, JSFunction, \
cached_or_new_service) \
V(RESOLVE_LOCALE_FUNCTION_INDEX, JSFunction, resolve_locale) \
V(SET_ADD_INDEX, JSFunction, set_add) \
V(SET_DELETE_INDEX, JSFunction, set_delete) \
V(SET_HAS_INDEX, JSFunction, set_has) \
V(SYNTAX_ERROR_FUNCTION_INDEX, JSFunction, syntax_error_function) \
V(TYPE_ERROR_FUNCTION_INDEX, JSFunction, type_error_function) \
V(URI_ERROR_FUNCTION_INDEX, JSFunction, uri_error_function) \
V(WASM_COMPILE_ERROR_FUNCTION_INDEX, JSFunction, \
wasm_compile_error_function) \
V(WASM_LINK_ERROR_FUNCTION_INDEX, JSFunction, wasm_link_error_function) \
V(WASM_RUNTIME_ERROR_FUNCTION_INDEX, JSFunction, \
wasm_runtime_error_function) \
V(WEAKMAP_SET_INDEX, JSFunction, weakmap_set) \
#define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \
V(ARRAY_SHIFT_INDEX, JSFunction, array_shift) \
V(ARRAY_UNSHIFT_INDEX, JSFunction, array_unshift) \
V(ARRAY_ENTRIES_ITERATOR_INDEX, JSFunction, array_entries_iterator) \
V(ARRAY_FOR_EACH_ITERATOR_INDEX, JSFunction, array_for_each_iterator) \
V(ARRAY_KEYS_ITERATOR_INDEX, JSFunction, array_keys_iterator) \
V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) \
V(CANONICALIZE_LOCALE_LIST_FUNCTION_INDEX, JSFunction, \
canonicalize_locale_list) \
V(ERROR_FUNCTION_INDEX, JSFunction, error_function) \
V(ERROR_TO_STRING, JSFunction, error_to_string) \
V(EVAL_ERROR_FUNCTION_INDEX, JSFunction, eval_error_function) \
V(GLOBAL_EVAL_FUN_INDEX, JSFunction, global_eval_fun) \
V(GLOBAL_PROXY_FUNCTION_INDEX, JSFunction, global_proxy_function) \
V(MAP_DELETE_INDEX, JSFunction, map_delete) \
V(MAP_GET_INDEX, JSFunction, map_get) \
V(MAP_HAS_INDEX, JSFunction, map_has) \
V(MAP_SET_INDEX, JSFunction, map_set) \
V(FUNCTION_HAS_INSTANCE_INDEX, JSFunction, function_has_instance) \
V(OBJECT_VALUE_OF, JSFunction, object_value_of) \
V(OBJECT_TO_STRING, JSFunction, object_to_string) \
V(PROMISE_CATCH_INDEX, JSFunction, promise_catch) \
V(PROMISE_FUNCTION_INDEX, JSFunction, promise_function) \
V(RANGE_ERROR_FUNCTION_INDEX, JSFunction, range_error_function) \
V(REFERENCE_ERROR_FUNCTION_INDEX, JSFunction, reference_error_function) \
V(CACHED_OR_NEW_SERVICE_LOCALE_FUNCTION_INDEX, JSFunction, \
cached_or_new_service) \
V(RESOLVE_LOCALE_FUNCTION_INDEX, JSFunction, resolve_locale) \
V(SET_ADD_INDEX, JSFunction, set_add) \
V(SET_DELETE_INDEX, JSFunction, set_delete) \
V(SET_HAS_INDEX, JSFunction, set_has) \
V(SYNTAX_ERROR_FUNCTION_INDEX, JSFunction, syntax_error_function) \
V(TYPE_ERROR_FUNCTION_INDEX, JSFunction, type_error_function) \
V(URI_ERROR_FUNCTION_INDEX, JSFunction, uri_error_function) \
V(WASM_COMPILE_ERROR_FUNCTION_INDEX, JSFunction, \
wasm_compile_error_function) \
V(WASM_LINK_ERROR_FUNCTION_INDEX, JSFunction, wasm_link_error_function) \
V(WASM_RUNTIME_ERROR_FUNCTION_INDEX, JSFunction, \
wasm_runtime_error_function) \
V(WEAKMAP_SET_INDEX, JSFunction, weakmap_set) \
V(WEAKSET_ADD_INDEX, JSFunction, weakset_add)
#define NATIVE_CONTEXT_FIELDS(V) \
......
......@@ -724,18 +724,6 @@ class ElementsAccessorBase : public InternalElementsAccessor {
UNREACHABLE();
}
Handle<JSArray> Splice(Handle<JSArray> receiver, uint32_t start,
uint32_t delete_count, Arguments* args,
uint32_t add_count) final {
return Subclass::SpliceImpl(receiver, start, delete_count, args, add_count);
}
static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
uint32_t start, uint32_t delete_count,
Arguments* args, uint32_t add_count) {
UNREACHABLE();
}
Handle<Object> Pop(Handle<JSArray> receiver) final {
return Subclass::PopImpl(receiver);
}
......@@ -2227,58 +2215,6 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
return result_array;
}
static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
uint32_t start, uint32_t delete_count,
Arguments* args, uint32_t add_count) {
Isolate* isolate = receiver->GetIsolate();
Heap* heap = isolate->heap();
uint32_t length = Smi::ToInt(receiver->length());
uint32_t new_length = length - delete_count + add_count;
ElementsKind kind = KindTraits::Kind;
if (new_length <= static_cast<uint32_t>(receiver->elements()->length()) &&
IsSmiOrObjectElementsKind(kind)) {
HandleScope scope(isolate);
JSObject::EnsureWritableFastElements(receiver);
}
Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
if (new_length == 0) {
receiver->set_elements(ReadOnlyRoots(heap).empty_fixed_array());
receiver->set_length(Smi::kZero);
return isolate->factory()->NewJSArrayWithElements(
backing_store, KindTraits::Kind, delete_count);
}
// Construct the result array which holds the deleted elements.
Handle<JSArray> deleted_elements = isolate->factory()->NewJSArray(
KindTraits::Kind, delete_count, delete_count);
if (delete_count > 0) {
DisallowHeapAllocation no_gc;
Subclass::CopyElementsImpl(isolate, *backing_store, start,
deleted_elements->elements(), KindTraits::Kind,
0, kPackedSizeNotKnown, delete_count);
}
// Delete and move elements to make space for add_count new elements.
if (add_count < delete_count) {
Subclass::SpliceShrinkStep(isolate, receiver, backing_store, start,
delete_count, add_count, length, new_length);
} else if (add_count > delete_count) {
backing_store =
Subclass::SpliceGrowStep(isolate, receiver, backing_store, start,
delete_count, add_count, length, new_length);
}
// Copy over the arguments.
Subclass::CopyArguments(args, backing_store, add_count, 3, start);
receiver->set_length(Smi::FromInt(new_length));
Subclass::TryTransitionResultArrayToPacked(deleted_elements);
return deleted_elements;
}
static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
Handle<FixedArrayBase> backing_store, int dst_index,
int src_index, int len, int hole_start,
......@@ -2503,50 +2439,6 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
return result;
}
private:
// SpliceShrinkStep might modify the backing_store.
static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver,
Handle<FixedArrayBase> backing_store,
uint32_t start, uint32_t delete_count,
uint32_t add_count, uint32_t len,
uint32_t new_length) {
const int move_left_count = len - delete_count - start;
const int move_left_dst_index = start + add_count;
Subclass::MoveElements(isolate, receiver, backing_store,
move_left_dst_index, start + delete_count,
move_left_count, new_length, len);
}
// SpliceGrowStep might modify the backing_store.
static Handle<FixedArrayBase> SpliceGrowStep(
Isolate* isolate, Handle<JSArray> receiver,
Handle<FixedArrayBase> backing_store, uint32_t start,
uint32_t delete_count, uint32_t add_count, uint32_t length,
uint32_t new_length) {
// Check we do not overflow the new_length.
DCHECK((add_count - delete_count) <= (Smi::kMaxValue - length));
// Check if backing_store is big enough.
if (new_length <= static_cast<uint32_t>(backing_store->length())) {
Subclass::MoveElements(isolate, receiver, backing_store,
start + add_count, start + delete_count,
(length - delete_count - start), 0, 0);
// MoveElements updates the backing_store in-place.
return backing_store;
}
// New backing storage is needed.
int capacity = JSObject::NewElementsCapacity(new_length);
// Partially copy all elements up to start.
Handle<FixedArrayBase> new_elms = Subclass::ConvertElementsWithCapacity(
receiver, backing_store, KindTraits::Kind, capacity, start);
// Copy the trailing elements after start + delete_count
Subclass::CopyElementsImpl(isolate, *backing_store, start + delete_count,
*new_elms, KindTraits::Kind, start + add_count,
kPackedSizeNotKnown,
ElementsAccessor::kCopyToEndAndInitializeToHole);
receiver->set_elements(*new_elms);
return new_elms;
}
static Handle<Object> RemoveElement(Handle<JSArray> receiver,
Where remove_position) {
Isolate* isolate = receiver->GetIsolate();
......
......@@ -135,10 +135,6 @@ class ElementsAccessor {
virtual Handle<JSObject> Slice(Handle<JSObject> receiver, uint32_t start,
uint32_t end) = 0;
virtual Handle<JSArray> Splice(Handle<JSArray> receiver,
uint32_t start, uint32_t delete_count,
Arguments* args, uint32_t add_count) = 0;
virtual Handle<Object> Pop(Handle<JSArray> receiver) = 0;
virtual Handle<Object> Shift(Handle<JSArray> receiver) = 0;
......
......@@ -874,8 +874,6 @@ DEFINE_BOOL(expose_trigger_failure, false, "expose trigger-failure extension")
DEFINE_INT(stack_trace_limit, 10, "number of stack frames to capture")
DEFINE_BOOL(builtins_in_stack_traces, false,
"show built-in functions in stack traces")
DEFINE_BOOL(enable_experimental_builtins, false,
"enable new csa-based experimental builtins")
DEFINE_BOOL(disallow_code_generation_from_strings, false,
"disallow eval and friends")
DEFINE_BOOL(expose_async_hooks, false, "expose async_hooks object")
......
......@@ -200,35 +200,6 @@ function ConvertToString(use_locale, x, locales, options) {
return TO_STRING(x);
}
// This function implements the optimized splice implementation that can use
// special array operations to handle sparse arrays in a sensible fashion.
function SparseSlice(array, start_i, del_count, len, deleted_elements) {
// Move deleted elements to a new array (the return value from splice).
var indices = %GetArrayKeys(array, start_i + del_count);
if (IS_NUMBER(indices)) {
var limit = indices;
for (var i = start_i; i < limit; ++i) {
var current = array[i];
if (!IS_UNDEFINED(current) || i in array) {
%CreateDataProperty(deleted_elements, i - start_i, current);
}
}
} else {
var length = indices.length;
for (var k = 0; k < length; ++k) {
var key = indices[k];
if (key >= start_i) {
var current = array[key];
if (!IS_UNDEFINED(current) || key in array) {
%CreateDataProperty(deleted_elements, key - start_i, current);
}
}
}
}
}
// This function implements the optimized splice implementation that can use
// special array operations to handle sparse arrays in a sensible fashion.
function SparseMove(array, start_i, del_count, len, num_additional_args) {
......@@ -442,83 +413,6 @@ function ArraySliceFallback(start, end) {
return null;
}
function ComputeSpliceStartIndex(start_i, len) {
if (start_i < 0) {
start_i += len;
return start_i < 0 ? 0 : start_i;
}
return start_i > len ? len : start_i;
}
function ComputeSpliceDeleteCount(delete_count, num_arguments, len, start_i) {
// SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
// given as a request to delete all the elements from the start.
// And it differs from the case of undefined delete count.
// This does not follow ECMA-262, but we do the same for
// compatibility.
var del_count = 0;
if (num_arguments == 1)
return len - start_i;
del_count = TO_INTEGER(delete_count);
if (del_count < 0)
return 0;
if (del_count > len - start_i)
return len - start_i;
return del_count;
}
function ArraySpliceFallback(start, delete_count) {
var num_arguments = arguments.length;
var array = TO_OBJECT(this);
var len = TO_LENGTH(array.length);
var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len);
var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len,
start_i);
var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0;
const new_len = len - del_count + num_elements_to_add;
if (new_len >= 2**53) throw %make_type_error(kInvalidArrayLength);
var deleted_elements = ArraySpeciesCreate(array, del_count);
deleted_elements.length = del_count;
var changed_elements = del_count;
if (num_elements_to_add != del_count) {
// If the slice needs to do a actually move elements after the insertion
// point, then include those in the estimate of changed elements.
changed_elements += len - start_i - del_count;
}
if (UseSparseVariant(array, len, IS_ARRAY(array), changed_elements)) {
%NormalizeElements(array);
if (IS_ARRAY(deleted_elements)) %NormalizeElements(deleted_elements);
SparseSlice(array, start_i, del_count, len, deleted_elements);
SparseMove(array, start_i, del_count, len, num_elements_to_add);
} else {
SimpleSlice(array, start_i, del_count, len, deleted_elements);
SimpleMove(array, start_i, del_count, len, num_elements_to_add);
}
// Insert the arguments into the resulting array in
// place of the deleted elements.
var i = start_i;
var arguments_index = 2;
var arguments_length = arguments.length;
while (arguments_index < arguments_length) {
array[i++] = arguments[arguments_index++];
}
array.length = new_len;
// Return the deleted elements.
return deleted_elements;
}
function InnerArraySort(array, length, comparefn) {
// In-place QuickSort algorithm.
// For short (length <= 10) arrays, insertion sort is used for efficiency.
......@@ -755,7 +649,6 @@ utils.Export(function(to) {
"array_keys_iterator", ArrayKeys,
"array_values_iterator", ArrayValues,
// Fallback implementations of Array builtins.
"array_splice", ArraySpliceFallback,
"array_unshift", ArrayUnshiftFallback,
]);
......
......@@ -30,6 +30,16 @@ RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
return *object;
}
RUNTIME_FUNCTION(Runtime_TransitionElementsKindWithKind) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
CONVERT_ARG_HANDLE_CHECKED(Smi, elements_kind_smi, 1);
ElementsKind to_kind = static_cast<ElementsKind>(elements_kind_smi->value());
JSObject::TransitionElementsKind(object, to_kind);
return *object;
}
namespace {
// Find the next free position. undefined and holes are both considered
// free spots. Returns "Nothing" if an exception occurred.
......
......@@ -36,21 +36,22 @@ namespace internal {
// A variable number of arguments is specified by a -1, additional restrictions
// are specified by inline comments
#define FOR_EACH_INTRINSIC_ARRAY(F) \
F(ArrayIncludes_Slow, 3, 1) \
F(ArrayIndexOf, 3, 1) \
F(ArrayIsArray, 1, 1) \
F(ArraySpeciesConstructor, 1, 1) \
F(EstimateNumberOfElements, 1, 1) \
F(GetArrayKeys, 2, 1) \
F(GrowArrayElements, 2, 1) \
F(HasComplexElements, 1, 1) \
F(IsArray, 1, 1) \
F(MoveArrayContents, 2, 1) \
F(NewArray, -1 /* >= 3 */, 1) \
F(NormalizeElements, 1, 1) \
F(PrepareElementsForSort, 2, 1) \
F(TransitionElementsKind, 2, 1) \
#define FOR_EACH_INTRINSIC_ARRAY(F) \
F(ArrayIncludes_Slow, 3, 1) \
F(ArrayIndexOf, 3, 1) \
F(ArrayIsArray, 1, 1) \
F(ArraySpeciesConstructor, 1, 1) \
F(EstimateNumberOfElements, 1, 1) \
F(GetArrayKeys, 2, 1) \
F(GrowArrayElements, 2, 1) \
F(HasComplexElements, 1, 1) \
F(IsArray, 1, 1) \
F(MoveArrayContents, 2, 1) \
F(NewArray, -1 /* >= 3 */, 1) \
F(NormalizeElements, 1, 1) \
F(PrepareElementsForSort, 2, 1) \
F(TransitionElementsKind, 2, 1) \
F(TransitionElementsKindWithKind, 2, 1) \
F(TrySliceSimpleNonFastElements, 3, 1)
#define FOR_EACH_INTRINSIC_ATOMICS(F) \
......
......@@ -31,13 +31,8 @@
* should work on other objects too, so we test that too.
*/
var LARGE = 400000;
var VERYLARGE = 4000000000;
// Nicer for firefox 1.5. Unless you uncomment the following two lines,
// smjs will appear to hang on this file.
//var LARGE = 40000;
//var VERYLARGE = 40000;
var LARGE = 40000;
var VERYLARGE = 40000;
var fourhundredth = LARGE/400;
......
......@@ -445,3 +445,21 @@
"array.hasOwnProperty(Math.pow(2, 32) - 2)");
}
})();
// Verify that fast implementations aren't confused by empty DOUBLE element arrays
(function() {
function foo(dontAddAnything) {
let a = [];
if (dontAddAnything === undefined) {
a[1] = 0.5;
}
return a.splice(0, 0, 3.5);
}
// Learn via allocation site tracking to create double arrays in foo().
foo();
foo();
// force splice to copy the input array.
foo(true);
})();
// 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:
var a = [5.65];
a.splice(0);
var b = a.splice(-4, 9, 10);
......@@ -32,10 +32,3 @@ assertEquals(0xffffffff, a.length);
assertEquals(10, a[0xffffffff]);
assertEquals(0xffffffff, a.length);
assertEquals(undefined, a[0xfffffffe]);
a = [1,2,3];
a[0xfffffffe] = 10;
assertThrows("a.splice(1,1,7,7,7,7,7);", RangeError);
assertEquals([1,7,7,7,7,7,3], a.slice(0, 7));
assertEquals(0xffffffff, a.length);
assertEquals(10, a[0xfffffffe + 5 - 1]);
......@@ -184,6 +184,11 @@
# characters. This takes a long time to run (~32 seconds).
'js1_5/GC/regress-348532': [SKIP],
# Takes a really long time to run, creating an Array of length
# 2^32 - 1. Related to removal of "sparse" array support for
# splice and friends:
# https://bugs.chromium.org/p/v8/issues/detail?id=8131.
'ecma_3/Array/regress-322135-03': [SKIP],
# Runs for too long: huge array with getters and setters. As it says
# in the test: "This test will probably run out of memory".
......
......@@ -598,9 +598,6 @@
'intl402/Locale/prototype/toStringTag/toStringTag': [FAIL],
'intl402/Locale/prototype/toStringTag/toString': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=7814
'built-ins/Array/prototype/splice/property-traps-order-with-species': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=6705
'built-ins/Object/assign/strings-and-symbol-order': [FAIL],
......@@ -683,8 +680,6 @@
# https://bugs.chromium.org/p/v8/issues/detail?id=6538
'built-ins/Array/prototype/unshift/throws-if-integer-limit-exceeded': [SKIP],
'built-ins/Array/prototype/splice/create-species-length-exceeding-integer-limit': [FAIL],
'built-ins/Array/prototype/splice/throws-if-integer-limit-exceeded': [SKIP],
# https://bugs.chromium.org/p/v8/issues/detail?id=6541
'language/export/escaped-as-export-specifier': [FAIL],
......
......@@ -54,8 +54,3 @@ shouldBe("arr.splice(2, -1)", "[]")
shouldBe("arr", "['a','b','c']");
shouldBe("arr.splice(2, 100)", "['c']")
shouldBe("arr", "['a','b']");
// Check this doesn't crash.
try {
String(Array(0xFFFFFFFD).splice(0));
} catch (e) { }
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