Commit a4f5c696 authored by Simon Zünd's avatar Simon Zünd Committed by Commit Bot

[array] Move Array.p.lastIndexOf from JS to Torque

This CL re-implements Array.p.lastIndexOf in Torque. The implementation
consists of a generic baseline path and a fast-path for JSArrays with fast
ElementsKinds.

Sparse support for JSArrays was removed.

Bug: v8:7624
Change-Id: I6ae877aaf99fa97a91763b3d60a0ee05623ab085
Reviewed-on: https://chromium-review.googlesource.com/1190345
Commit-Queue: Simon Zünd <szuend@google.com>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55451}
parent 4af6bd00
......@@ -887,6 +887,7 @@ torque_files = [
"src/builtins/array.tq",
"src/builtins/array-copywithin.tq",
"src/builtins/array-foreach.tq",
"src/builtins/array-lastindexof.tq",
"src/builtins/array-reverse.tq",
"src/builtins/typed-array.tq",
"src/builtins/data-view.tq",
......
......@@ -1731,6 +1731,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Builtins::kArrayPrototypeFind, 1, false);
SimpleInstallFunction(isolate_, proto, "findIndex",
Builtins::kArrayPrototypeFindIndex, 1, false);
SimpleInstallFunction(isolate_, proto, "lastIndexOf",
Builtins::kArrayPrototypeLastIndexOf, 1, false);
SimpleInstallFunction(isolate_, proto, "pop", Builtins::kArrayPrototypePop,
0, false);
SimpleInstallFunction(isolate_, proto, "push",
......
// 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 {
macro LoadWithHoleCheck<Elements : type>(
elements: FixedArrayBase, index: Smi): Object
labels IfHole;
LoadWithHoleCheck<FixedArray>(elements: FixedArrayBase, index: Smi): Object
labels IfHole {
const elements: FixedArray = unsafe_cast<FixedArray>(elements);
const element: Object = elements[index];
if (element == Hole) goto IfHole;
return element;
}
LoadWithHoleCheck<FixedDoubleArray>(
elements: FixedArrayBase, index: Smi): Object
labels IfHole {
const elements: FixedDoubleArray = unsafe_cast<FixedDoubleArray>(elements);
const element: float64 = LoadDoubleWithHoleCheck(elements, index)
otherwise IfHole;
return AllocateHeapNumberWithValue(element);
}
macro FastArrayLastIndexOf<Elements : type>(
context: Context, array: JSArray, length: Smi, from: Smi,
searchElement: Object): Smi {
const elements: FixedArrayBase = array.elements;
let k: Smi = from;
while (k >= 0) {
try {
const element: Object = LoadWithHoleCheck<Elements>(elements, k)
otherwise Hole;
const same: Boolean = StrictEqual(searchElement, element);
if (same == True) {
assert(IsFastJSArray(array, context));
return k;
}
}
label Hole {} // Do nothing for holes.
--k;
}
assert(IsFastJSArray(array, context));
return -1;
}
macro GetFromIndex(
context: Context, length: Number,
arguments: constexpr Arguments): Number {
// 4. If fromIndex is present, let n be ? ToInteger(fromIndex);
// else let n be len - 1.
const n: Number = arguments.length < 2 ?
length - 1 :
ToInteger_Inline(context, arguments[1], kTruncateMinusZero);
// 5. If n >= 0, then.
let k: Number = SmiConstant(0);
if (n >= 0) {
// a. If n is -0, let k be +0; else let k be min(n, len - 1).
// If n was -0 it got truncated to 0.0, so taking the minimum is fine.
k = min(n, length - 1);
} else {
// a. Let k be len + n.
k = length + n;
}
return k;
}
macro TryFastArrayLastIndexOf(
context: Context, receiver: Object,
arguments: constexpr Arguments): Object
labels Slow {
EnsureFastJSArray(context, receiver) otherwise Slow;
const array: JSArray = unsafe_cast<JSArray>(receiver);
const length: Smi = array.length_fast;
if (length == 0) return SmiConstant(-1);
const from: Smi = cast<Smi>(GetFromIndex(context, length, arguments))
otherwise Slow;
const kind: ElementsKind = array.map.elements_kind;
if (IsFastSmiOrTaggedElementsKind(kind)) {
return FastArrayLastIndexOf<FixedArray>(
context, array, length, from, arguments[0]);
}
assert(IsDoubleElementsKind(kind));
return FastArrayLastIndexOf<FixedDoubleArray>(
context, array, length, from, arguments[0]);
}
macro GenericArrayLastIndexOf(
context: Context, receiver: Object,
arguments: constexpr Arguments): Object {
// 1. Let O be ? ToObject(this value).
const object: JSReceiver = ToObject_Inline(context, receiver);
// 2. Let len be ? ToLength(? Get(O, "length")).
const length: Number = GetLengthProperty(context, object);
// 3. If len is 0, return -1.
if (length == SmiConstant(0)) return SmiConstant(-1);
const search_element: Object = arguments[0];
// Step 4 - 6.
let k: Number = GetFromIndex(context, length, arguments);
// 7. Repeat, while k >= 0.
while (k >= 0) {
// a. Let kPresent be ? HasProperty(O, ! ToString(k)).
const k_present: Boolean = HasProperty(context, object, k);
// b. If kPresent is true, then.
if (k_present == True) {
// i. Let elementK be ? Get(O, ! ToString(k)).
const element: Object = GetProperty(context, object, k);
// ii. Let same be the result of performing Strict Equality Comparison
// searchElement === elementK.
const same: Boolean = StrictEqual(search_element, element);
// iii. If same is true, return k.
if (same == True) return k;
}
// c. Decrease k by 1.
--k;
}
// 8. Return -1.
return SmiConstant(-1);
}
// https://tc39.github.io/ecma262/#sec-array.prototype.lastIndexOf
javascript builtin ArrayPrototypeLastIndexOf(
context: Context, receiver: Object, ...arguments): Object {
try {
return TryFastArrayLastIndexOf(context, receiver, arguments)
otherwise Baseline;
}
label Baseline {
return GenericArrayLastIndexOf(context, receiver, arguments);
}
}
}
......@@ -609,6 +609,10 @@ extern macro BranchIfFastJSArray(Object, Context): never labels Taken, NotTaken;
extern macro BranchIfNotFastJSArray(Object, Context): never labels Taken,
NotTaken;
macro EnsureFastJSArray(context: Context, object: Object) labels Bailout {
if (BranchIfNotFastJSArray(object, context)) goto Bailout;
}
extern macro IsPrototypeInitialArrayPrototype(Context, Map): bool;
extern macro IsNoElementsProtectorCellInvalid(): bool;
extern macro IsArraySpeciesProtectorCellInvalid(): bool;
......@@ -743,6 +747,7 @@ extern macro IsHeapNumber(HeapObject): bool;
extern macro IsFixedArray(HeapObject): bool;
extern macro IsExtensibleMap(Map): bool;
extern macro IsCustomElementsReceiverInstanceType(int32): bool;
extern macro IsFastJSArray(Object, Context): bool;
extern macro Typeof(Object): Object;
// Return true iff number is NaN.
......
......@@ -561,6 +561,7 @@ DebugInfo::SideEffectState BuiltinGetSideEffectState(Builtins::Name id) {
case Builtins::kArrayPrototypeFlat:
case Builtins::kArrayPrototypeFlatMap:
case Builtins::kArrayPrototypeKeys:
case Builtins::kArrayPrototypeLastIndexOf:
case Builtins::kArrayPrototypeSlice:
case Builtins::kArrayPrototypeSort:
case Builtins::kArrayForEach:
......
......@@ -700,56 +700,6 @@ function InnerArraySort(array, length, comparefn) {
}
DEFINE_METHOD_LEN(
GlobalArray.prototype,
lastIndexOf(element, index) {
var array = TO_OBJECT(this);
var length = TO_LENGTH(this.length);
if (length == 0) return -1;
if (arguments.length < 2) {
index = length - 1;
} else {
index = INVERT_NEG_ZERO(TO_INTEGER(index));
// If index is negative, index from end of the array.
if (index < 0) index += length;
// If index is still negative, do not search the array.
if (index < 0) return -1;
else if (index >= length) index = length - 1;
}
var min = 0;
var max = index;
if (UseSparseVariant(array, length, IS_ARRAY(array), index)) {
%NormalizeElements(array);
var indices = %GetArrayKeys(array, index + 1);
if (IS_NUMBER(indices)) {
// It's an interval.
max = indices; // Capped by index already.
// Fall through to loop below.
} else {
if (indices.length == 0) return -1;
// Get all the keys in sorted order.
var sortedKeys = GetSortedArrayKeys(array, indices);
var i = sortedKeys.length - 1;
while (i >= 0) {
var key = sortedKeys[i];
if (array[key] === element) return key;
i--;
}
return -1;
}
}
// Lookup through the array.
for (var i = max; i >= min; i--) {
if (i in array && array[i] === element) return i;
}
return -1;
},
1 /* Set function length */
);
// Set up unscopable properties on the Array.prototype object.
var unscopables = {
__proto__: null,
......
......@@ -1301,7 +1301,7 @@ TEST(CustomSnapshotDataBlobWithWarmup) {
CHECK(IsCompiled("Math.abs"));
CHECK(!IsCompiled("g"));
CHECK(IsCompiled("String.raw"));
CHECK(!IsCompiled("Array.prototype.lastIndexOf"));
CHECK(IsCompiled("Array.prototype.lastIndexOf"));
CHECK_EQ(5, CompileRun("a")->Int32Value(context).FromJust());
}
isolate->Dispose();
......
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