Commit da1bddcd authored by cwhan.tunz's avatar cwhan.tunz Committed by Commit bot

[typedarrays] Implement %TypedArray%.prototype.lastIndexOf in C++

- Implement C++ builtins and ElementsAccessor for
  %TypedArray%.prototype.lastIndexOf
- Remove TypedArrayLastIndexOf in src/js/typedarray.js
- Combine InnerArrayLastIndexOf and ArrayLastIndexOf in src/js/array.js

BUG=v8:5929

Review-Url: https://codereview.chromium.org/2744283002
Cr-Commit-Position: refs/heads/master@{#43870}
parent 17ac7c5f
......@@ -2602,6 +2602,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Builtins::kTypedArrayPrototypeIncludes, 1, false);
SimpleInstallFunction(prototype, "indexOf",
Builtins::kTypedArrayPrototypeIndexOf, 1, false);
SimpleInstallFunction(prototype, "lastIndexOf",
Builtins::kTypedArrayPrototypeLastIndexOf, 1, false);
}
{ // -- T y p e d A r r a y s
......
......@@ -172,5 +172,39 @@ BUILTIN(TypedArrayPrototypeIndexOf) {
return *isolate->factory()->NewNumberFromInt64(result.FromJust());
}
BUILTIN(TypedArrayPrototypeLastIndexOf) {
HandleScope scope(isolate);
Handle<JSTypedArray> array;
const char* method = "%TypedArray%.prototype.lastIndexOf";
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
int64_t len = array->length_value();
if (len == 0) return Smi::FromInt(-1);
int64_t index = len - 1;
if (args.length() > 2) {
Handle<Object> num;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, num, Object::ToInteger(isolate, args.at<Object>(2)));
// Set a negative value (-1) for returning -1 if num is negative and
// len + num is still negative. Upper bound is len - 1.
index = std::min<int64_t>(CapRelativeIndex(num, -1, len), len - 1);
}
if (index < 0) return Smi::FromInt(-1);
// TODO(cwhan.tunz): throw. See the above comment in CopyWithin.
if (V8_UNLIKELY(array->WasNeutered())) return Smi::FromInt(-1);
Handle<Object> search_element = args.atOrUndefined(isolate, 1);
ElementsAccessor* elements = array->GetElementsAccessor();
Maybe<int64_t> result = elements->LastIndexOfValue(
isolate, array, search_element, static_cast<uint32_t>(index));
MAYBE_RETURN(result, isolate->heap()->exception());
return *isolate->factory()->NewNumberFromInt64(result.FromJust());
}
} // namespace internal
} // namespace v8
......@@ -845,6 +845,8 @@ class Isolate;
CPP(TypedArrayPrototypeIncludes) \
/* ES6 #sec-%typedarray%.prototype.indexof */ \
CPP(TypedArrayPrototypeIndexOf) \
/* ES6 #sec-%typedarray%.prototype.indexof */ \
CPP(TypedArrayPrototypeLastIndexOf) \
\
/* Wasm */ \
TFS(WasmStackGuard, BUILTIN, kNoExtraICState, WasmRuntimeCall, 1) \
......
......@@ -1219,6 +1219,20 @@ class ElementsAccessorBase : public ElementsAccessor {
length);
}
static Maybe<int64_t> LastIndexOfValueImpl(Isolate* isolate,
Handle<JSObject> receiver,
Handle<Object> value,
uint32_t start_from) {
UNREACHABLE();
return Just<int64_t>(-1);
}
Maybe<int64_t> LastIndexOfValue(Isolate* isolate, Handle<JSObject> receiver,
Handle<Object> value,
uint32_t start_from) final {
return Subclass::LastIndexOfValueImpl(isolate, receiver, value, start_from);
}
static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
uint32_t entry) {
return entry;
......@@ -2915,6 +2929,47 @@ class TypedElementsAccessor
}
return Just<int64_t>(-1);
}
static Maybe<int64_t> LastIndexOfValueImpl(Isolate* isolate,
Handle<JSObject> receiver,
Handle<Object> value,
uint32_t start_from) {
DisallowHeapAllocation no_gc;
DCHECK(!WasNeutered(*receiver));
if (!value->IsNumber()) return Just<int64_t>(-1);
BackingStore* elements = BackingStore::cast(receiver->elements());
double search_value = value->Number();
if (!std::isfinite(search_value)) {
if (std::is_integral<ctype>::value) {
// Integral types cannot represent +Inf or NaN.
return Just<int64_t>(-1);
} else if (std::isnan(search_value)) {
// Strict Equality Comparison of NaN is always false.
return Just<int64_t>(-1);
}
} else if (search_value < std::numeric_limits<ctype>::lowest() ||
search_value > std::numeric_limits<ctype>::max()) {
// Return -1 if value can't be represented in this ElementsKind.
return Just<int64_t>(-1);
}
ctype typed_search_value = static_cast<ctype>(search_value);
if (static_cast<double>(typed_search_value) != search_value) {
return Just<int64_t>(-1); // Loss of precision.
}
DCHECK_LT(start_from, elements->length());
uint32_t k = start_from;
do {
ctype element_k = elements->get_scalar(k);
if (element_k == typed_search_value) return Just<int64_t>(k);
} while (k-- != 0);
return Just<int64_t>(-1);
}
};
#define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
......
......@@ -171,6 +171,11 @@ class ElementsAccessor {
Handle<Object> value, uint32_t start,
uint32_t length) = 0;
virtual Maybe<int64_t> LastIndexOfValue(Isolate* isolate,
Handle<JSObject> receiver,
Handle<Object> value,
uint32_t start) = 0;
virtual void CopyElements(Handle<FixedArrayBase> source,
ElementsKind source_kind,
Handle<FixedArrayBase> destination, int size) = 0;
......
......@@ -1134,9 +1134,14 @@ function ArrayMap(f, receiver) {
}
function InnerArrayLastIndexOf(array, element, index, length, argumentsLength) {
function ArrayLastIndexOf(element, index) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.lastIndexOf");
var array = this;
var length = TO_LENGTH(this.length);
if (length == 0) return -1;
if (argumentsLength < 2) {
if (arguments.length < 2) {
index = length - 1;
} else {
index = INVERT_NEG_ZERO(TO_INTEGER(index));
......@@ -1184,15 +1189,6 @@ function InnerArrayLastIndexOf(array, element, index, length, argumentsLength) {
}
function ArrayLastIndexOf(element, index) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.lastIndexOf");
var length = TO_LENGTH(this.length);
return InnerArrayLastIndexOf(this, element, index, length,
arguments.length);
}
function InnerArrayReduce(callback, current, array, length, argumentsLength) {
if (!IS_CALLABLE(callback)) {
throw %make_type_error(kCalledNonCallable, callback);
......@@ -1628,7 +1624,6 @@ utils.Export(function(to) {
to.InnerArrayFindIndex = InnerArrayFindIndex;
to.InnerArrayForEach = InnerArrayForEach;
to.InnerArrayJoin = InnerArrayJoin;
to.InnerArrayLastIndexOf = InnerArrayLastIndexOf;
to.InnerArrayReduce = InnerArrayReduce;
to.InnerArrayReduceRight = InnerArrayReduceRight;
to.InnerArraySome = InnerArraySome;
......
......@@ -470,46 +470,6 @@ function TypedArraySort(comparefn) {
}
// ES6 section 22.2.3.16
function TypedArrayLastIndexOf(element, index) {
if (!IS_TYPEDARRAY(this)) throw %make_type_error(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
if (length === 0) return -1;
if (!IS_NUMBER(element)) return -1;
var n;
if (arguments.length < 2) {
n = length - 1;
} else {
n = TO_INTEGER(index);
}
var k;
if (n >= 0) {
if (length <= n) {
k = length - 1;
} else if (n === 0) {
k = 0;
} else {
k = n;
}
} else {
k = length + n;
}
while (k >= 0) {
var elementK = this[k];
if (element === elementK) {
return k;
}
--k;
}
return -1;
}
%FunctionSetLength(TypedArrayLastIndexOf, 1);
// ES6 draft 07-15-13, section 22.2.3.18
function TypedArrayMap(f, thisArg) {
if (!IS_TYPEDARRAY(this)) throw %make_type_error(kNotTypedArray);
......@@ -703,7 +663,6 @@ utils.InstallFunctions(GlobalTypedArray.prototype, DONT_ENUM, [
"find", TypedArrayFind,
"findIndex", TypedArrayFindIndex,
"join", TypedArrayJoin,
"lastIndexOf", TypedArrayLastIndexOf,
"forEach", TypedArrayForEach,
"map", TypedArrayMap,
"reduce", TypedArrayReduce,
......
......@@ -42,6 +42,16 @@ for (var constructor of typedArrayConstructors) {
Object.defineProperty(array, 'length', {value: 1});
assertEquals(array.indexOf(2), 1);
// Index of infinite value
array = new constructor([NaN, 2, 3, +Infinity, -Infinity, 5, 6]);
if (constructor == Float32Array || constructor == Float64Array) {
assertEquals(3, array.indexOf(Infinity));
assertEquals(4, array.indexOf(-Infinity));
} else {
assertEquals(-1, array.indexOf(Infinity));
assertEquals(-1, array.indexOf(-Infinity));
}
assertEquals(-1, array.indexOf(NaN));
// ----------------------------------------------------------------------
// %TypedArray%.prototype.lastIndexOf.
......@@ -68,4 +78,15 @@ for (var constructor of typedArrayConstructors) {
Object.defineProperty(array, 'length', {value: 1});
assertEquals(array.lastIndexOf(2), 10);
delete array.length;
// Index of infinite value
array = new constructor([NaN, 2, 3, +Infinity, -Infinity, 5, 6]);
if (constructor == Float32Array || constructor == Float64Array) {
assertEquals(3, array.lastIndexOf(Infinity));
assertEquals(4, array.lastIndexOf(-Infinity));
} else {
assertEquals(-1, array.lastIndexOf(Infinity));
assertEquals(-1, array.lastIndexOf(-Infinity));
}
assertEquals(-1, array.lastIndexOf(NaN));
}
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