[call reducer] inline Array.prototype.indexOf/includes in js-call-reducer.
- inline Array.prototype.indexOf in js-call-reducer - inline Array.prototype.includes in js-call-reducer Bug: v8:12390 Change-Id: Idb5669da3019f0f56af0084fccd1d616d4c5098e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3473994 Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Marja Hölttä <marja@chromium.org> Commit-Queue: Marja Hölttä <marja@chromium.org> Cr-Commit-Position: refs/heads/main@{#79461}
This commit is contained in:
parent
8a0d1b6fe5
commit
9f9f36f875
@ -265,6 +265,8 @@ class JSCallReducerAssembler : public JSGraphAssembler {
|
|||||||
|
|
||||||
// Common operators.
|
// Common operators.
|
||||||
TNode<Smi> TypeGuardUnsignedSmall(TNode<Object> value);
|
TNode<Smi> TypeGuardUnsignedSmall(TNode<Object> value);
|
||||||
|
TNode<Number> TypeGuardNumber(TNode<Object> value);
|
||||||
|
TNode<String> TypeGuardString(TNode<Object> value);
|
||||||
TNode<Object> TypeGuardNonInternal(TNode<Object> value);
|
TNode<Object> TypeGuardNonInternal(TNode<Object> value);
|
||||||
TNode<Number> TypeGuardFixedArrayLength(TNode<Object> value);
|
TNode<Number> TypeGuardFixedArrayLength(TNode<Object> value);
|
||||||
TNode<Object> Call4(const Callable& callable, TNode<Context> context,
|
TNode<Object> Call4(const Callable& callable, TNode<Context> context,
|
||||||
@ -519,12 +521,15 @@ class JSCallReducerAssembler : public JSGraphAssembler {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ForBuilder0 ForZeroUntil(TNode<Number> excluded_limit) {
|
ForBuilder0 ForZeroUntil(TNode<Number> excluded_limit) {
|
||||||
TNode<Number> initial_value = ZeroConstant();
|
return ForStartUntil(ZeroConstant(), excluded_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
ForBuilder0 ForStartUntil(TNode<Number> start, TNode<Number> excluded_limit) {
|
||||||
auto cond = [=](TNode<Number> i) {
|
auto cond = [=](TNode<Number> i) {
|
||||||
return NumberLessThan(i, excluded_limit);
|
return NumberLessThan(i, excluded_limit);
|
||||||
};
|
};
|
||||||
auto step = [=](TNode<Number> i) { return NumberAdd(i, OneConstant()); };
|
auto step = [=](TNode<Number> i) { return NumberAdd(i, OneConstant()); };
|
||||||
return {this, initial_value, cond, step};
|
return {this, start, cond, step};
|
||||||
}
|
}
|
||||||
|
|
||||||
ForBuilder0 Forever(TNode<Number> initial_value, const StepFunction1& step) {
|
ForBuilder0 Forever(TNode<Number> initial_value, const StepFunction1& step) {
|
||||||
@ -1047,6 +1052,14 @@ TNode<Smi> JSCallReducerAssembler::TypeGuardUnsignedSmall(TNode<Object> value) {
|
|||||||
return TNode<Smi>::UncheckedCast(TypeGuard(Type::UnsignedSmall(), value));
|
return TNode<Smi>::UncheckedCast(TypeGuard(Type::UnsignedSmall(), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TNode<Number> JSCallReducerAssembler::TypeGuardNumber(TNode<Object> value) {
|
||||||
|
return TNode<Smi>::UncheckedCast(TypeGuard(Type::Number(), value));
|
||||||
|
}
|
||||||
|
|
||||||
|
TNode<String> JSCallReducerAssembler::TypeGuardString(TNode<Object> value) {
|
||||||
|
return TNode<String>::UncheckedCast(TypeGuard(Type::String(), value));
|
||||||
|
}
|
||||||
|
|
||||||
TNode<Object> JSCallReducerAssembler::TypeGuardNonInternal(
|
TNode<Object> JSCallReducerAssembler::TypeGuardNonInternal(
|
||||||
TNode<Object> value) {
|
TNode<Object> value) {
|
||||||
return TNode<Object>::UncheckedCast(TypeGuard(Type::NonInternal(), value));
|
return TNode<Object>::UncheckedCast(TypeGuard(Type::NonInternal(), value));
|
||||||
@ -1983,38 +1996,33 @@ namespace {
|
|||||||
Callable GetCallableForArrayIndexOfIncludes(ArrayIndexOfIncludesVariant variant,
|
Callable GetCallableForArrayIndexOfIncludes(ArrayIndexOfIncludesVariant variant,
|
||||||
ElementsKind elements_kind,
|
ElementsKind elements_kind,
|
||||||
Isolate* isolate) {
|
Isolate* isolate) {
|
||||||
|
DCHECK(IsHoleyElementsKind(elements_kind));
|
||||||
if (variant == ArrayIndexOfIncludesVariant::kIndexOf) {
|
if (variant == ArrayIndexOfIncludesVariant::kIndexOf) {
|
||||||
switch (elements_kind) {
|
switch (elements_kind) {
|
||||||
case PACKED_SMI_ELEMENTS:
|
|
||||||
case HOLEY_SMI_ELEMENTS:
|
case HOLEY_SMI_ELEMENTS:
|
||||||
case PACKED_ELEMENTS:
|
|
||||||
case HOLEY_ELEMENTS:
|
case HOLEY_ELEMENTS:
|
||||||
return Builtins::CallableFor(isolate,
|
return Builtins::CallableFor(isolate,
|
||||||
Builtin::kArrayIndexOfSmiOrObject);
|
Builtin::kArrayIndexOfSmiOrObject);
|
||||||
case PACKED_DOUBLE_ELEMENTS:
|
case HOLEY_DOUBLE_ELEMENTS:
|
||||||
return Builtins::CallableFor(isolate,
|
|
||||||
Builtin::kArrayIndexOfPackedDoubles);
|
|
||||||
default:
|
|
||||||
DCHECK_EQ(HOLEY_DOUBLE_ELEMENTS, elements_kind);
|
|
||||||
return Builtins::CallableFor(isolate,
|
return Builtins::CallableFor(isolate,
|
||||||
Builtin::kArrayIndexOfHoleyDoubles);
|
Builtin::kArrayIndexOfHoleyDoubles);
|
||||||
|
default: {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DCHECK_EQ(variant, ArrayIndexOfIncludesVariant::kIncludes);
|
DCHECK_EQ(variant, ArrayIndexOfIncludesVariant::kIncludes);
|
||||||
switch (elements_kind) {
|
switch (elements_kind) {
|
||||||
case PACKED_SMI_ELEMENTS:
|
|
||||||
case HOLEY_SMI_ELEMENTS:
|
case HOLEY_SMI_ELEMENTS:
|
||||||
case PACKED_ELEMENTS:
|
|
||||||
case HOLEY_ELEMENTS:
|
case HOLEY_ELEMENTS:
|
||||||
return Builtins::CallableFor(isolate,
|
return Builtins::CallableFor(isolate,
|
||||||
Builtin::kArrayIncludesSmiOrObject);
|
Builtin::kArrayIncludesSmiOrObject);
|
||||||
case PACKED_DOUBLE_ELEMENTS:
|
case HOLEY_DOUBLE_ELEMENTS:
|
||||||
return Builtins::CallableFor(isolate,
|
|
||||||
Builtin::kArrayIncludesPackedDoubles);
|
|
||||||
default:
|
|
||||||
DCHECK_EQ(HOLEY_DOUBLE_ELEMENTS, elements_kind);
|
|
||||||
return Builtins::CallableFor(isolate,
|
return Builtins::CallableFor(isolate,
|
||||||
Builtin::kArrayIncludesHoleyDoubles);
|
Builtin::kArrayIncludesHoleyDoubles);
|
||||||
|
default: {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -2030,13 +2038,7 @@ IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeIndexOfIncludes(
|
|||||||
TNode<Object> search_element = ArgumentOrUndefined(0);
|
TNode<Object> search_element = ArgumentOrUndefined(0);
|
||||||
TNode<Object> from_index = ArgumentOrZero(1);
|
TNode<Object> from_index = ArgumentOrZero(1);
|
||||||
|
|
||||||
// TODO(jgruber): This currently only reduces to a stub call. Create a full
|
TNode<Number> original_length = LoadJSArrayLength(receiver, kind);
|
||||||
// reduction (similar to other higher-order array builtins) instead of
|
|
||||||
// lowering to a builtin call. E.g. Array.p.every and Array.p.some have almost
|
|
||||||
// identical functionality.
|
|
||||||
|
|
||||||
TNode<Number> length = LoadJSArrayLength(receiver, kind);
|
|
||||||
TNode<FixedArrayBase> elements = LoadElements(receiver);
|
|
||||||
|
|
||||||
const bool have_from_index = ArgumentCount() > 1;
|
const bool have_from_index = ArgumentCount() > 1;
|
||||||
if (have_from_index) {
|
if (have_from_index) {
|
||||||
@ -2046,18 +2048,279 @@ IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeIndexOfIncludes(
|
|||||||
// therefore needs to be added to the length. If the result is still
|
// therefore needs to be added to the length. If the result is still
|
||||||
// negative, it needs to be clamped to 0.
|
// negative, it needs to be clamped to 0.
|
||||||
TNode<Boolean> cond = NumberLessThan(from_index_smi, ZeroConstant());
|
TNode<Boolean> cond = NumberLessThan(from_index_smi, ZeroConstant());
|
||||||
from_index = SelectIf<Number>(cond)
|
from_index =
|
||||||
.Then(_ {
|
SelectIf<Number>(cond)
|
||||||
return NumberMax(NumberAdd(length, from_index_smi),
|
.Then(_ {
|
||||||
ZeroConstant());
|
return NumberMax(NumberAdd(original_length, from_index_smi),
|
||||||
})
|
ZeroConstant());
|
||||||
.Else(_ { return from_index_smi; })
|
})
|
||||||
.ExpectFalse()
|
.Else(_ { return from_index_smi; })
|
||||||
.Value();
|
.ExpectFalse()
|
||||||
|
.Value();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Call4(GetCallableForArrayIndexOfIncludes(variant, kind, isolate()),
|
if (IsHoleyElementsKind(kind)) {
|
||||||
context, elements, search_element, length, from_index);
|
TNode<FixedArrayBase> elements = LoadElements(receiver);
|
||||||
|
return Call4(GetCallableForArrayIndexOfIncludes(variant, kind, isolate()),
|
||||||
|
context, elements, search_element, original_length,
|
||||||
|
from_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto out = MakeLabel(MachineRepresentation::kTagged);
|
||||||
|
|
||||||
|
DCHECK(IsFastPackedElementsKind(kind));
|
||||||
|
|
||||||
|
Node* fail_value;
|
||||||
|
if (variant == ArrayIndexOfIncludesVariant::kIncludes) {
|
||||||
|
fail_value = FalseConstant();
|
||||||
|
} else {
|
||||||
|
fail_value = NumberConstant(-1);
|
||||||
|
}
|
||||||
|
TNode<FixedArrayBase> elements = LoadElements(receiver);
|
||||||
|
|
||||||
|
switch (kind) {
|
||||||
|
case PACKED_SMI_ELEMENTS: {
|
||||||
|
TNode<Boolean> is_finite_number = AddNode<Boolean>(graph()->NewNode(
|
||||||
|
simplified()->ObjectIsFiniteNumber(), search_element));
|
||||||
|
GotoIfNot(is_finite_number, &out, fail_value);
|
||||||
|
|
||||||
|
TNode<Number> search_element_number = TypeGuardNumber(search_element);
|
||||||
|
ForStartUntil(TNode<Number>::UncheckedCast(from_index), original_length)
|
||||||
|
.Do([&](TNode<Number> k) {
|
||||||
|
// if from_index is not smi, it will early bailout, so here
|
||||||
|
// we could LoadElement directly.
|
||||||
|
TNode<Object> element = LoadElement<Object>(
|
||||||
|
AccessBuilder::ForFixedArrayElement(kind), elements, k);
|
||||||
|
|
||||||
|
auto cond = NumberEqual(search_element_number,
|
||||||
|
TNode<Number>::UncheckedCast(element));
|
||||||
|
|
||||||
|
if (variant == ArrayIndexOfIncludesVariant::kIncludes) {
|
||||||
|
GotoIf(cond, &out, TrueConstant());
|
||||||
|
} else {
|
||||||
|
GotoIf(cond, &out, k);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Goto(&out, fail_value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PACKED_DOUBLE_ELEMENTS: {
|
||||||
|
auto nan_loop = MakeLabel();
|
||||||
|
TNode<Boolean> is_number = AddNode<Boolean>(
|
||||||
|
graph()->NewNode(simplified()->ObjectIsNumber(), search_element));
|
||||||
|
GotoIfNot(is_number, &out, fail_value);
|
||||||
|
|
||||||
|
TNode<Number> search_element_number = TypeGuardNumber(search_element);
|
||||||
|
|
||||||
|
if (variant == ArrayIndexOfIncludesVariant::kIncludes) {
|
||||||
|
// https://tc39.es/ecma262/#sec-array.prototype.includes use
|
||||||
|
// SameValueZero, NaN == NaN, so we need to check.
|
||||||
|
TNode<Boolean> is_nan = AddNode<Boolean>(graph()->NewNode(
|
||||||
|
simplified()->NumberIsNaN(), search_element_number));
|
||||||
|
GotoIf(is_nan, &nan_loop);
|
||||||
|
} else {
|
||||||
|
DCHECK(variant == ArrayIndexOfIncludesVariant::kIndexOf);
|
||||||
|
// https://tc39.es/ecma262/#sec-array.prototype.indexOf use
|
||||||
|
// IsStrictEqual, NaN != NaN, NaN compare will be handled by
|
||||||
|
// NumberEqual.
|
||||||
|
}
|
||||||
|
|
||||||
|
ForStartUntil(TNode<Number>::UncheckedCast(from_index), original_length)
|
||||||
|
.Do([&](TNode<Number> k) {
|
||||||
|
TNode<Object> element = LoadElement<Object>(
|
||||||
|
AccessBuilder::ForFixedArrayElement(kind), elements, k);
|
||||||
|
|
||||||
|
auto cond = NumberEqual(search_element_number,
|
||||||
|
TNode<Number>::UncheckedCast(element));
|
||||||
|
|
||||||
|
if (variant == ArrayIndexOfIncludesVariant::kIncludes) {
|
||||||
|
GotoIf(cond, &out, TrueConstant());
|
||||||
|
} else {
|
||||||
|
GotoIf(cond, &out, k);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Goto(&out, fail_value);
|
||||||
|
|
||||||
|
// https://tc39.es/ecma262/#sec-array.prototype.includes use
|
||||||
|
// SameValueZero, NaN == NaN, we need to bind nan_loop to check.
|
||||||
|
if (variant == ArrayIndexOfIncludesVariant::kIncludes) {
|
||||||
|
Bind(&nan_loop);
|
||||||
|
ForStartUntil(TNode<Number>::UncheckedCast(from_index), original_length)
|
||||||
|
.Do([&](TNode<Number> k) {
|
||||||
|
TNode<Object> element = LoadElement<Object>(
|
||||||
|
AccessBuilder::ForFixedArrayElement(kind), elements, k);
|
||||||
|
|
||||||
|
auto cond = AddNode<Boolean>(
|
||||||
|
graph()->NewNode(simplified()->NumberIsNaN(),
|
||||||
|
TNode<Number>::UncheckedCast(element)));
|
||||||
|
GotoIf(cond, &out, TrueConstant());
|
||||||
|
});
|
||||||
|
Goto(&out, fail_value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PACKED_ELEMENTS: {
|
||||||
|
auto number_loop = MakeLabel();
|
||||||
|
auto not_number = MakeLabel();
|
||||||
|
auto string_loop = MakeLabel();
|
||||||
|
auto bigint_loop = MakeLabel();
|
||||||
|
auto ident_loop = MakeLabel();
|
||||||
|
|
||||||
|
auto is_number = AddNode(
|
||||||
|
graph()->NewNode(simplified()->ObjectIsNumber(), search_element));
|
||||||
|
GotoIf(is_number, &number_loop);
|
||||||
|
Goto(¬_number);
|
||||||
|
|
||||||
|
Bind(¬_number);
|
||||||
|
auto is_string = AddNode(
|
||||||
|
graph()->NewNode(simplified()->ObjectIsString(), search_element));
|
||||||
|
GotoIf(is_string, &string_loop);
|
||||||
|
auto is_bigint = AddNode(
|
||||||
|
graph()->NewNode(simplified()->ObjectIsBigInt(), search_element));
|
||||||
|
GotoIf(is_bigint, &bigint_loop);
|
||||||
|
|
||||||
|
Goto(&ident_loop);
|
||||||
|
Bind(&ident_loop);
|
||||||
|
|
||||||
|
ForStartUntil(TNode<Number>::UncheckedCast(from_index), original_length)
|
||||||
|
.Do([&](TNode<Number> k) {
|
||||||
|
// if from_index is not smi, it will early bailout, so here
|
||||||
|
// we could LoadElement directly.
|
||||||
|
TNode<Object> element = LoadElement<Object>(
|
||||||
|
AccessBuilder::ForFixedArrayElement(kind), elements, k);
|
||||||
|
auto cond = AddNode(graph()->NewNode(simplified()->ReferenceEqual(),
|
||||||
|
search_element, element));
|
||||||
|
if (variant == ArrayIndexOfIncludesVariant::kIncludes) {
|
||||||
|
GotoIf(cond, &out, TrueConstant());
|
||||||
|
} else {
|
||||||
|
GotoIf(cond, &out, k);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Goto(&out, fail_value);
|
||||||
|
|
||||||
|
Bind(&number_loop);
|
||||||
|
TNode<Number> search_element_number = TypeGuardNumber(search_element);
|
||||||
|
|
||||||
|
auto nan_loop = MakeLabel();
|
||||||
|
|
||||||
|
if (variant == ArrayIndexOfIncludesVariant::kIncludes) {
|
||||||
|
// https://tc39.es/ecma262/#sec-array.prototype.includes use
|
||||||
|
// SameValueZero, NaN == NaN, so we need to check.
|
||||||
|
auto is_nan = AddNode(graph()->NewNode(simplified()->NumberIsNaN(),
|
||||||
|
search_element_number));
|
||||||
|
GotoIf(is_nan, &nan_loop);
|
||||||
|
} else {
|
||||||
|
DCHECK(variant == ArrayIndexOfIncludesVariant::kIndexOf);
|
||||||
|
// https://tc39.es/ecma262/#sec-array.prototype.indexOf use
|
||||||
|
// IsStrictEqual, NaN != NaN, NaN compare will be handled by
|
||||||
|
// NumberEqual.
|
||||||
|
}
|
||||||
|
|
||||||
|
ForStartUntil(TNode<Number>::UncheckedCast(from_index), original_length)
|
||||||
|
.Do([&](TNode<Number> k) {
|
||||||
|
auto continue_label = MakeLabel();
|
||||||
|
TNode<Object> element = LoadElement<Object>(
|
||||||
|
AccessBuilder::ForFixedArrayElement(kind), elements, k);
|
||||||
|
|
||||||
|
auto is_number = AddNode(
|
||||||
|
graph()->NewNode(simplified()->ObjectIsNumber(), element));
|
||||||
|
|
||||||
|
GotoIfNot(is_number, &continue_label);
|
||||||
|
|
||||||
|
TNode<Number> element_number = TypeGuardNumber(element);
|
||||||
|
auto cond = NumberEqual(search_element_number, element_number);
|
||||||
|
GotoIfNot(cond, &continue_label);
|
||||||
|
if (variant == ArrayIndexOfIncludesVariant::kIncludes) {
|
||||||
|
Goto(&out, TrueConstant());
|
||||||
|
} else {
|
||||||
|
Goto(&out, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bind(&continue_label);
|
||||||
|
});
|
||||||
|
Goto(&out, fail_value);
|
||||||
|
|
||||||
|
// https://tc39.es/ecma262/#sec-array.prototype.includes use
|
||||||
|
// SameValueZero, NaN == NaN, we need to bind nan_loop to check.
|
||||||
|
if (variant == ArrayIndexOfIncludesVariant::kIncludes) {
|
||||||
|
Bind(&nan_loop);
|
||||||
|
ForStartUntil(TNode<Number>::UncheckedCast(from_index), original_length)
|
||||||
|
.Do([&](TNode<Number> k) {
|
||||||
|
TNode<Object> element = LoadElement<Object>(
|
||||||
|
AccessBuilder::ForFixedArrayElement(kind), elements, k);
|
||||||
|
|
||||||
|
auto cond = AddNode<Boolean>(
|
||||||
|
graph()->NewNode(simplified()->ObjectIsNaN(), element));
|
||||||
|
GotoIf(cond, &out, TrueConstant());
|
||||||
|
});
|
||||||
|
Goto(&out, fail_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bind(&string_loop);
|
||||||
|
TNode<String> search_element_string = TypeGuardString(search_element);
|
||||||
|
ForStartUntil(TNode<Number>::UncheckedCast(from_index), original_length)
|
||||||
|
.Do([&](TNode<Number> k) {
|
||||||
|
auto continue_label = MakeLabel();
|
||||||
|
TNode<Object> element = LoadElement<Object>(
|
||||||
|
AccessBuilder::ForFixedArrayElement(kind), elements, k);
|
||||||
|
auto is_string = AddNode(
|
||||||
|
graph()->NewNode(simplified()->ObjectIsString(), element));
|
||||||
|
|
||||||
|
GotoIfNot(is_string, &continue_label);
|
||||||
|
|
||||||
|
TNode<String> element_string = TypeGuardString(element);
|
||||||
|
auto cond = AddNode(graph()->NewNode(simplified()->StringEqual(),
|
||||||
|
element_string,
|
||||||
|
search_element_string));
|
||||||
|
GotoIfNot(cond, &continue_label);
|
||||||
|
if (variant == ArrayIndexOfIncludesVariant::kIncludes) {
|
||||||
|
Goto(&out, TrueConstant());
|
||||||
|
} else {
|
||||||
|
Goto(&out, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bind(&continue_label);
|
||||||
|
});
|
||||||
|
Goto(&out, fail_value);
|
||||||
|
|
||||||
|
Bind(&bigint_loop);
|
||||||
|
ForStartUntil(TNode<Number>::UncheckedCast(from_index), original_length)
|
||||||
|
.Do([&](TNode<Number> k) {
|
||||||
|
auto continue_label = MakeLabel();
|
||||||
|
TNode<Object> element = LoadElement<Object>(
|
||||||
|
AccessBuilder::ForFixedArrayElement(kind), elements, k);
|
||||||
|
auto is_bigint = AddNode(
|
||||||
|
graph()->NewNode(simplified()->ObjectIsBigInt(), element));
|
||||||
|
|
||||||
|
GotoIfNot(is_bigint, &continue_label);
|
||||||
|
auto cond = AddNode<Object>(graph()->NewNode(
|
||||||
|
javascript()->CallRuntime(Runtime::kBigIntEqualToBigInt, 2),
|
||||||
|
search_element, element, context, FrameStateInput(), effect(),
|
||||||
|
control()));
|
||||||
|
|
||||||
|
GotoIfNot(ToBoolean(cond), &continue_label);
|
||||||
|
if (variant == ArrayIndexOfIncludesVariant::kIncludes) {
|
||||||
|
Goto(&out, TrueConstant());
|
||||||
|
} else {
|
||||||
|
Goto(&out, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bind(&continue_label);
|
||||||
|
});
|
||||||
|
Goto(&out, fail_value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Bind(&out);
|
||||||
|
if (variant == ArrayIndexOfIncludesVariant::kIncludes) {
|
||||||
|
return out.PhiAt<Boolean>(0);
|
||||||
|
} else {
|
||||||
|
return out.PhiAt<Number>(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
67
test/js-perf-test/Array/includes.js
Normal file
67
test/js-perf-test/Array/includes.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2022 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.
|
||||||
|
(() => {
|
||||||
|
|
||||||
|
function make_includes() {
|
||||||
|
return new Function('result = array.includes(target)');
|
||||||
|
}
|
||||||
|
|
||||||
|
createSuite('SmiIncludes', 1000, make_includes(), SmiIncludesSetup);
|
||||||
|
createSuite('SparseSmiIncludes', 1000, make_includes(), SparseSmiIncludesSetup);
|
||||||
|
createSuite('DoubleIncludes', 1000, make_includes(), SmiIncludesSetup);
|
||||||
|
createSuite('SparseDoubleIncludes', 1000, make_includes(), SparseSmiIncludesSetup);
|
||||||
|
createSuite('ObjectIncludes', 1000, make_includes(), SmiIncludesSetup);
|
||||||
|
createSuite('SparseObjectIncludes', 1000, make_includes(), SparseSmiIncludesSetup);
|
||||||
|
createSuite('StringIncludes', 1000, make_includes(), StringIncludesSetup);
|
||||||
|
createSuite('SparseStringIncludes', 1000, make_includes(), SparseStringIncludesSetup);
|
||||||
|
|
||||||
|
function SmiIncludesSetup() {
|
||||||
|
array = new Array();
|
||||||
|
for (let i = 0; i < array_size; ++i) array[i] = i;
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function SparseSmiIncludesSetup() {
|
||||||
|
SmiIncludesSetup();
|
||||||
|
array.length = array.length * 2;
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function StringIncludesSetup() {
|
||||||
|
array = new Array();
|
||||||
|
for (let i = 0; i < array_size; ++i) array[i] = `Item no. ${i}`;
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function SparseStringIncludesSetup() {
|
||||||
|
StringIncludesSetup();
|
||||||
|
array.length = array.length * 2;
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function DoubleIncludesSetup() {
|
||||||
|
array = new Array();
|
||||||
|
for (let i = 0; i < array_size; ++i) array[i] = i;
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function SparseDoubleIncludesSetup() {
|
||||||
|
DoubleIncludesSetup();
|
||||||
|
array.length = array.length * 2;
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function ObjectIncludesSetup() {
|
||||||
|
array = new Array();
|
||||||
|
for (let i = 0; i < array_size; ++i) array[i] = {i};
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function SparseObjectIncludesSetup() {
|
||||||
|
ObjectIncludesSetup();
|
||||||
|
array.length = array.length * 2;
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
67
test/js-perf-test/Array/index-of.js
Normal file
67
test/js-perf-test/Array/index-of.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2022 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.
|
||||||
|
(() => {
|
||||||
|
|
||||||
|
function make_indexOf() {
|
||||||
|
return new Function('result = array.indexOf(target)');
|
||||||
|
}
|
||||||
|
|
||||||
|
createSuite('SmiIndexOf', 1000, make_indexOf(), SmiIndexOfSetup);
|
||||||
|
createSuite('SparseSmiIndexOf', 1000, make_indexOf(), SparseSmiIndexOfSetup);
|
||||||
|
createSuite('DoubleIndexOf', 1000, make_indexOf(), SmiIndexOfSetup);
|
||||||
|
createSuite('SparseDoubleIndexOf', 1000, make_indexOf(), SparseSmiIndexOfSetup);
|
||||||
|
createSuite('ObjectIndexOf', 1000, make_indexOf(), SmiIndexOfSetup);
|
||||||
|
createSuite('SparseObjectIndexOf', 1000, make_indexOf(), SparseSmiIndexOfSetup);
|
||||||
|
createSuite('StringIndexOf', 1000, make_indexOf(), StringIndexOfSetup);
|
||||||
|
createSuite('SparseStringIndexOf', 1000, make_indexOf(), SparseStringIndexOfSetup);
|
||||||
|
|
||||||
|
function SmiIndexOfSetup() {
|
||||||
|
array = new Array();
|
||||||
|
for (let i = 0; i < array_size; ++i) array[i] = i;
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function SparseSmiIndexOfSetup() {
|
||||||
|
SmiIndexOfSetup();
|
||||||
|
array.length = array.length * 2;
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function StringIndexOfSetup() {
|
||||||
|
array = new Array();
|
||||||
|
for (let i = 0; i < array_size; ++i) array[i] = `Item no. ${i}`;
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function SparseStringIndexOfSetup() {
|
||||||
|
StringIndexOfSetup();
|
||||||
|
array.length = array.length * 2;
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function DoubleIndexOfSetup() {
|
||||||
|
array = new Array();
|
||||||
|
for (let i = 0; i < array_size; ++i) array[i] = i;
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function SparseDoubleIndexOfSetup() {
|
||||||
|
DoubleIndexOfSetup();
|
||||||
|
array.length = array.length * 2;
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function ObjectIndexOfSetup() {
|
||||||
|
array = new Array();
|
||||||
|
for (let i = 0; i < array_size; ++i) array[i] = {i};
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function SparseObjectIndexOfSetup() {
|
||||||
|
ObjectIndexOfSetup();
|
||||||
|
array.length = array.length * 2;
|
||||||
|
target = array[array_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
@ -10,6 +10,7 @@ let array;
|
|||||||
let func = 0;
|
let func = 0;
|
||||||
let this_arg;
|
let this_arg;
|
||||||
let result;
|
let result;
|
||||||
|
let target;
|
||||||
const array_size = 100;
|
const array_size = 100;
|
||||||
const max_index = array_size - 1;
|
const max_index = array_size - 1;
|
||||||
// Matches what {FastSetup} below produces.
|
// Matches what {FastSetup} below produces.
|
||||||
@ -141,6 +142,8 @@ d8.file.execute('join.js');
|
|||||||
d8.file.execute('to-string.js');
|
d8.file.execute('to-string.js');
|
||||||
d8.file.execute('slice.js');
|
d8.file.execute('slice.js');
|
||||||
d8.file.execute('copy-within.js');
|
d8.file.execute('copy-within.js');
|
||||||
|
d8.file.execute('index-of.js')
|
||||||
|
d8.file.execute('includes.js')
|
||||||
|
|
||||||
var success = true;
|
var success = true;
|
||||||
|
|
||||||
|
@ -60,7 +60,8 @@
|
|||||||
"resources": [
|
"resources": [
|
||||||
"filter.js", "map.js", "every.js", "join.js", "some.js", "reduce.js",
|
"filter.js", "map.js", "every.js", "join.js", "some.js", "reduce.js",
|
||||||
"reduce-right.js", "to-string.js", "find.js", "find-index.js",
|
"reduce-right.js", "to-string.js", "find.js", "find-index.js",
|
||||||
"from.js", "of.js", "for-each.js", "slice.js", "copy-within.js"
|
"from.js", "of.js", "for-each.js", "slice.js", "copy-within.js",
|
||||||
|
"index-of.js", "includes.js"
|
||||||
],
|
],
|
||||||
"flags": [
|
"flags": [
|
||||||
"--allow-natives-syntax"
|
"--allow-natives-syntax"
|
||||||
@ -181,7 +182,23 @@
|
|||||||
{"name": "SmiCopyWithin"},
|
{"name": "SmiCopyWithin"},
|
||||||
{"name": "StringCopyWithin"},
|
{"name": "StringCopyWithin"},
|
||||||
{"name": "SparseSmiCopyWithin"},
|
{"name": "SparseSmiCopyWithin"},
|
||||||
{"name": "SparseStringCopyWithin"}
|
{"name": "SparseStringCopyWithin"},
|
||||||
|
{"name": "SmiIndexOf"},
|
||||||
|
{"name": "SparseSmiIndexOf"},
|
||||||
|
{"name": "DoubleIndexOf"},
|
||||||
|
{"name": "SparseDoubleIndexOf"},
|
||||||
|
{"name": "ObjectIndexOf"},
|
||||||
|
{"name": "SparseObjectIndexOf"},
|
||||||
|
{"name": "StringIndexOf"},
|
||||||
|
{"name": "SparseStringIncludes"},
|
||||||
|
{"name": "SmiIncludes"},
|
||||||
|
{"name": "SparseSmiIncludes"},
|
||||||
|
{"name": "DoubleIncludes"},
|
||||||
|
{"name": "SparseDoubleIncludes"},
|
||||||
|
{"name": "ObjectIncludes"},
|
||||||
|
{"name": "SparseObjectIncludes"},
|
||||||
|
{"name": "StringIncludes"},
|
||||||
|
{"name": "SparseStringIncludes"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
358
test/mjsunit/optimized-array-includes.js
Normal file
358
test/mjsunit/optimized-array-includes.js
Normal file
@ -0,0 +1,358 @@
|
|||||||
|
// Copyright 2022 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 --turbo-inline-array-builtins --opt
|
||||||
|
// Flags: --no-always-opt
|
||||||
|
|
||||||
|
// normal case
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(20, 0);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
testArrayIncludes();
|
||||||
|
assertOptimized(testArrayIncludes);
|
||||||
|
})();
|
||||||
|
|
||||||
|
// from_index is not smi will lead to bailout
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(20, {
|
||||||
|
valueOf: () => {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertFalse(isOptimized(testArrayIncludes));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Length change detected during get from_index, will bailout
|
||||||
|
(() => {
|
||||||
|
let called_values;
|
||||||
|
function testArrayIncludes(deopt) {
|
||||||
|
const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||||
|
return a.includes(9, {
|
||||||
|
valueOf: () => {
|
||||||
|
if (deopt) {
|
||||||
|
a.length = 3;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
testArrayIncludes();
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertEquals(false, testArrayIncludes(true));
|
||||||
|
assertFalse(isOptimized(testArrayIncludes));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Input array change during get from_index, will bailout
|
||||||
|
(() => {
|
||||||
|
const a = [1, 2, 3, 4, 5];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(9, {
|
||||||
|
valueOf: () => {
|
||||||
|
a[0] = 9;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
testArrayIncludes();
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertFalse(isOptimized(testArrayIncludes));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle from_index is undefined, will bail out
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(20, undefined);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertFalse(isOptimized(testArrayIncludes));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle from_index is null, will bail out
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(20, undefined);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertFalse(isOptimized(testArrayIncludes));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle from_index is float, will bail out
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(20, 0.5);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertFalse(isOptimized(testArrayIncludes));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle from_index is symbol, will throw
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(20, Symbol.for('123'));
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
assertThrows(() => testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
assertThrows(() => testArrayIncludes());
|
||||||
|
assertFalse(isOptimized(testArrayIncludes));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle from_index is string, will bailout
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(20, '0');
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
testArrayIncludes()
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertFalse(isOptimized(testArrayIncludes));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle from_index is object which cannot convert to smi, will throw
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(20, {
|
||||||
|
valueOf: () => {
|
||||||
|
return Symbol.for('123')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
assertThrows(() => testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
assertThrows(() => testArrayIncludes());
|
||||||
|
assertFalse(isOptimized(testArrayIncludes));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle input array is smi packed elements and search_element is number
|
||||||
|
// , will be inlined
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(20);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertOptimized(testArrayIncludes);
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle input array is double packed elements, will be inlined
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5,
|
||||||
|
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
|
||||||
|
19.5, 20.5, 21.5, 22.5, 23.5, 24.5, 25.5
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(20.5);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertOptimized(testArrayIncludes);
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle input array is double packed elements and has NaN, will be inlined
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
NaN, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5,
|
||||||
|
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
|
||||||
|
19.5, 20.5, 21.5, 22.5, 23.5, 24.5, 25.5
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(NaN);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertOptimized(testArrayIncludes);
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle input array is packed elements, will reach slow path
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5,
|
||||||
|
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
|
||||||
|
19.5, 20.5, 21.5, 22.5, 23.5, 24.5, {}
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(20.5);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertOptimized(testArrayIncludes);
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
// Handle input array is packed elements, will be inlined
|
||||||
|
(() => {
|
||||||
|
const obj = {}
|
||||||
|
const a = [
|
||||||
|
1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5,
|
||||||
|
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
|
||||||
|
19.5, 20.5, 21.5, 22.5, 23.5, 24.5, obj
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(obj);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertOptimized(testArrayIncludes);
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
// Handle input array is packed elements and search_element is symbol
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1.5, 2.5, Symbol.for("123"), "4.5", BigInt(123), 6.5, 7.5, 8.5, 9.5,
|
||||||
|
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
|
||||||
|
19.5, 20.5, 21.5, 22.5, 23.5, 24.5, {}
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(Symbol.for("123"));
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertOptimized(testArrayIncludes);
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle input array is packed elements and search_element is BigInt
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1.5, 2.5, Symbol.for("123"), "4.5", BigInt(123), 6.5, 7.5, 8.5, 9.5,
|
||||||
|
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
|
||||||
|
19.5, 20.5, 21.5, 22.5, 23.5, 24.5, {}
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes(BigInt(123));
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertOptimized(testArrayIncludes);
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle input array is packed elements and search_element is string
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1.5, 2.5, Symbol.for("123"), "4.5", BigInt(123), 6.5, 7.5, 8.5, 9.5,
|
||||||
|
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
|
||||||
|
19.5, 20.5, 21.5, 22.5, 23.5, 24.5, {}
|
||||||
|
];
|
||||||
|
function testArrayIncludes() {
|
||||||
|
return a.includes("4.5");
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIncludes);
|
||||||
|
testArrayIncludes();
|
||||||
|
assertEquals(true, testArrayIncludes());
|
||||||
|
assertOptimized(testArrayIncludes);
|
||||||
|
})();
|
360
test/mjsunit/optimized-array-indexof.js
Normal file
360
test/mjsunit/optimized-array-indexof.js
Normal file
@ -0,0 +1,360 @@
|
|||||||
|
// Copyright 2022 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 --turbo-inline-array-builtins --opt
|
||||||
|
// Flags: --no-always-opt
|
||||||
|
|
||||||
|
|
||||||
|
// normal case
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(20, 0);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertOptimized(testArrayIndexOf);
|
||||||
|
})();
|
||||||
|
|
||||||
|
// from_index is not smi will lead to bailout
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(20, {
|
||||||
|
valueOf: () => {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
assertFalse(isOptimized(testArrayIndexOf));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Length change detected during get from_index, will bailout
|
||||||
|
(() => {
|
||||||
|
let called_values;
|
||||||
|
function testArrayIndexOf(deopt) {
|
||||||
|
const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||||
|
return a.indexOf(9, {
|
||||||
|
valueOf: () => {
|
||||||
|
if (deopt) {
|
||||||
|
a.length = 3;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
assertEquals(8, testArrayIndexOf());
|
||||||
|
testArrayIndexOf();
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
assertEquals(8, testArrayIndexOf());
|
||||||
|
assertEquals(-1, testArrayIndexOf(true));
|
||||||
|
assertFalse(isOptimized(testArrayIndexOf));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Input array change during get from_index, will bailout
|
||||||
|
(() => {
|
||||||
|
function testArrayIndexOf(deopt) {
|
||||||
|
const a = [1, 2, 3, 4, 5];
|
||||||
|
return a.indexOf(9, {
|
||||||
|
valueOf: () => {
|
||||||
|
if (deopt) {
|
||||||
|
a[0] = 9;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
assertEquals(-1, testArrayIndexOf());
|
||||||
|
testArrayIndexOf();
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
assertEquals(0, testArrayIndexOf(true));
|
||||||
|
assertEquals(-1, testArrayIndexOf());
|
||||||
|
assertFalse(isOptimized(testArrayIndexOf));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle from_index is undefined, will bail out
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(20, undefined);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
assertFalse(isOptimized(testArrayIndexOf));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle from_index is null, will bail out
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(20, undefined);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
assertFalse(isOptimized(testArrayIndexOf));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle from_index is float, will bail out
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(20, 0.5);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
assertFalse(isOptimized(testArrayIndexOf));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle from_index is symbol, will throw
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(20, Symbol.for('123'));
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
assertThrows(() => testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
assertThrows(() => testArrayIndexOf());
|
||||||
|
assertFalse(isOptimized(testArrayIndexOf));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle from_index is string, will bailout
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(20, '0');
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
testArrayIndexOf()
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
assertFalse(isOptimized(testArrayIndexOf));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle from_index is object which cannot convert to smi, will throw
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(20, {
|
||||||
|
valueOf: () => {
|
||||||
|
return Symbol.for('123')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
assertThrows(() => testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
assertThrows(() => testArrayIndexOf());
|
||||||
|
assertFalse(isOptimized(testArrayIndexOf));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle input array is smi packed elements and search_element is number
|
||||||
|
// , will be inlined
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(20);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
assertOptimized(testArrayIndexOf);
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle input array is double packed elements, will be inlined
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5,
|
||||||
|
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
|
||||||
|
19.5, 20.5, 21.5, 22.5, 23.5, 24.5, 25.5
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(20.5);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
assertOptimized(testArrayIndexOf);
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle input array is double packed elements and has NaN, will be inlined
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
NaN, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5,
|
||||||
|
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
|
||||||
|
19.5, 20.5, 21.5, 22.5, 23.5, 24.5, 25.5
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(NaN);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(-1, testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(-1, testArrayIndexOf());
|
||||||
|
assertOptimized(testArrayIndexOf);
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle input array is packed elements and search_element is double,
|
||||||
|
// will be inlined
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1.5, 2.5, Symbol.for("123"), "4.5", BigInt(123), 6.5, 7.5, 8.5, 9.5,
|
||||||
|
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
|
||||||
|
19.5, 20.5, 21.5, 22.5, 23.5, 24.5, {}
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(20.5);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(19, testArrayIndexOf());
|
||||||
|
assertOptimized(testArrayIndexOf);
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
// Handle input array is packed elements and search_element is object,
|
||||||
|
// will be inlined
|
||||||
|
(() => {
|
||||||
|
const obj = {}
|
||||||
|
const a = [
|
||||||
|
1.5, 2.5, Symbol.for("123"), "4.5", BigInt(123), 6.5, 7.5, 8.5, 9.5,
|
||||||
|
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
|
||||||
|
19.5, 20.5, 21.5, 22.5, 23.5, 24.5, obj
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(obj);
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(24, testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(24, testArrayIndexOf());
|
||||||
|
assertOptimized(testArrayIndexOf);
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle input array is packed elements and search_element is symbol,
|
||||||
|
// will be inlined
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1.5, 2.5, Symbol.for("123"), "4.5", BigInt(123), 6.5, 7.5, 8.5, 9.5,
|
||||||
|
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
|
||||||
|
19.5, 20.5, 21.5, 22.5, 23.5, 24.5, {}
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(Symbol.for("123"));
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(2, testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(2, testArrayIndexOf());
|
||||||
|
assertOptimized(testArrayIndexOf);
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle input array is packed elements and search_element is BigInt,
|
||||||
|
// will be inlined
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1.5, 2.5, Symbol.for("123"), "4.5", BigInt(123), 6.5, 7.5, 8.5, 9.5,
|
||||||
|
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
|
||||||
|
19.5, 20.5, 21.5, 22.5, 23.5, 24.5, {}
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf(BigInt(123));
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(4, testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(4, testArrayIndexOf());
|
||||||
|
assertOptimized(testArrayIndexOf);
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Handle input array is packed elements and search_element is string,
|
||||||
|
// will be inlined
|
||||||
|
(() => {
|
||||||
|
const a = [
|
||||||
|
1.5, 2.5, Symbol.for("123"), "4.5", BigInt(123), 6.5, 7.5, 8.5, 9.5,
|
||||||
|
10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
|
||||||
|
19.5, 20.5, 21.5, 22.5, 23.5, 24.5, {}
|
||||||
|
];
|
||||||
|
function testArrayIndexOf() {
|
||||||
|
return a.indexOf("4.5");
|
||||||
|
}
|
||||||
|
%PrepareFunctionForOptimization(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(3, testArrayIndexOf());
|
||||||
|
%OptimizeFunctionOnNextCall(testArrayIndexOf);
|
||||||
|
testArrayIndexOf();
|
||||||
|
assertEquals(3, testArrayIndexOf());
|
||||||
|
assertOptimized(testArrayIndexOf);
|
||||||
|
})();
|
Loading…
Reference in New Issue
Block a user