Revert of [builtins] implement Array.prototype.includes in TurboFan (patchset #20 id:380001 of https://codereview.chromium.org/2146293003/ )
Reason for revert: [Sheriff] Breaks: https://build.chromium.org/p/client.v8.ports/builders/V8%20Arm%20-%20builder/builds/2592 Original issue's description: > [builtins] implement Array.prototype.includes in TurboFan > > BUG=v8:5162 > R=bmeurer@chromium.org, ishell@chromium.org > > Committed: https://crrev.com/a488b5d8eb111a4883dc400bd826d079420edd68 > Cr-Commit-Position: refs/heads/master@{#38223} TBR=adamk@chromium.org,bmeurer@chromium.org,cbruni@chromium.org,danno@chromium.org,ishell@chromium.org,littledan@chromium.org,caitp@igalia.com # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=v8:5162 Review-Url: https://codereview.chromium.org/2202163002 Cr-Commit-Position: refs/heads/master@{#38226}
This commit is contained in:
parent
a9d51f9e97
commit
c98f3a98d7
@ -4,8 +4,6 @@
|
||||
|
||||
#include "src/builtins/builtins.h"
|
||||
#include "src/builtins/builtins-utils.h"
|
||||
|
||||
#include "src/code-factory.h"
|
||||
#include "src/elements.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -57,9 +55,23 @@ inline bool GetSloppyArgumentsLength(Isolate* isolate, Handle<JSObject> object,
|
||||
return *out <= object->elements()->length();
|
||||
}
|
||||
|
||||
inline bool PrototypeHasNoElements(Isolate* isolate, JSObject* object) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
HeapObject* prototype = HeapObject::cast(object->map()->prototype());
|
||||
HeapObject* null = isolate->heap()->null_value();
|
||||
HeapObject* empty = isolate->heap()->empty_fixed_array();
|
||||
while (prototype != null) {
|
||||
Map* map = prototype->map();
|
||||
if (map->instance_type() <= LAST_CUSTOM_ELEMENTS_RECEIVER) return false;
|
||||
if (JSObject::cast(prototype)->elements() != empty) return false;
|
||||
prototype = HeapObject::cast(map->prototype());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate,
|
||||
JSArray* receiver) {
|
||||
return JSObject::PrototypeHasNoElements(isolate, receiver);
|
||||
return PrototypeHasNoElements(isolate, receiver);
|
||||
}
|
||||
|
||||
inline bool HasSimpleElements(JSObject* current) {
|
||||
@ -71,7 +83,7 @@ inline bool HasOnlySimpleReceiverElements(Isolate* isolate,
|
||||
JSObject* receiver) {
|
||||
// Check that we have no accessors on the receiver's elements.
|
||||
if (!HasSimpleElements(receiver)) return false;
|
||||
return JSObject::PrototypeHasNoElements(isolate, receiver);
|
||||
return PrototypeHasNoElements(isolate, receiver);
|
||||
}
|
||||
|
||||
inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) {
|
||||
@ -1259,485 +1271,5 @@ void Builtins::Generate_ArrayIsArray(CodeStubAssembler* assembler) {
|
||||
assembler->CallRuntime(Runtime::kArrayIsArray, context, object));
|
||||
}
|
||||
|
||||
void Builtins::Generate_ArrayIncludes(CodeStubAssembler* assembler) {
|
||||
typedef compiler::Node Node;
|
||||
typedef CodeStubAssembler::Label Label;
|
||||
typedef CodeStubAssembler::Variable Variable;
|
||||
|
||||
Node* array = assembler->Parameter(0);
|
||||
Node* search_element = assembler->Parameter(1);
|
||||
Node* start_from = assembler->Parameter(2);
|
||||
Node* context = assembler->Parameter(3 + 2);
|
||||
|
||||
Node* int32_zero = assembler->Int32Constant(0);
|
||||
Node* int32_one = assembler->Int32Constant(1);
|
||||
|
||||
Node* the_hole = assembler->TheHoleConstant();
|
||||
Node* undefined = assembler->UndefinedConstant();
|
||||
Node* heap_number_map = assembler->HeapNumberMapConstant();
|
||||
|
||||
Variable len_var(assembler, MachineRepresentation::kWord32),
|
||||
index_var(assembler, MachineRepresentation::kWord32),
|
||||
start_from_var(assembler, MachineRepresentation::kWord32);
|
||||
|
||||
Label init_k(assembler), return_true(assembler), return_false(assembler),
|
||||
call_runtime(assembler);
|
||||
|
||||
Label init_len(assembler);
|
||||
|
||||
index_var.Bind(int32_zero);
|
||||
len_var.Bind(int32_zero);
|
||||
|
||||
// Take slow path if not a JSArray, if retrieving elements requires
|
||||
// traversing prototype, or if access checks are required.
|
||||
assembler->BranchIfFastJSArray(array, context, &init_len, &call_runtime);
|
||||
|
||||
assembler->Bind(&init_len);
|
||||
{
|
||||
// Handle case where JSArray length is not an Smi in the runtime
|
||||
Node* len = assembler->LoadObjectField(array, JSArray::kLengthOffset);
|
||||
assembler->GotoUnless(assembler->WordIsSmi(len), &call_runtime);
|
||||
|
||||
len_var.Bind(assembler->SmiToWord(len));
|
||||
assembler->Branch(assembler->Word32Equal(len_var.value(), int32_zero),
|
||||
&return_false, &init_k);
|
||||
}
|
||||
|
||||
assembler->Bind(&init_k);
|
||||
{
|
||||
Label done(assembler), init_k_smi(assembler), init_k_heap_num(assembler),
|
||||
init_k_zero(assembler), init_k_n(assembler);
|
||||
Callable call_to_integer = CodeFactory::ToInteger(assembler->isolate());
|
||||
Node* tagged_n = assembler->CallStub(call_to_integer, context, start_from);
|
||||
|
||||
assembler->Branch(assembler->WordIsSmi(tagged_n), &init_k_smi,
|
||||
&init_k_heap_num);
|
||||
|
||||
assembler->Bind(&init_k_smi);
|
||||
{
|
||||
start_from_var.Bind(assembler->SmiToWord32(tagged_n));
|
||||
assembler->Goto(&init_k_n);
|
||||
}
|
||||
|
||||
assembler->Bind(&init_k_heap_num);
|
||||
{
|
||||
Label do_return_false(assembler);
|
||||
Node* fp_len = assembler->ChangeInt32ToFloat64(len_var.value());
|
||||
Node* fp_n = assembler->LoadHeapNumberValue(tagged_n);
|
||||
assembler->GotoIf(assembler->Float64GreaterThanOrEqual(fp_n, fp_len),
|
||||
&do_return_false);
|
||||
start_from_var.Bind(assembler->TruncateFloat64ToWord32(fp_n));
|
||||
assembler->Goto(&init_k_n);
|
||||
|
||||
assembler->Bind(&do_return_false);
|
||||
{
|
||||
index_var.Bind(int32_zero);
|
||||
assembler->Goto(&return_false);
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&init_k_n);
|
||||
{
|
||||
Label if_positive(assembler), if_negative(assembler), done(assembler);
|
||||
assembler->Branch(
|
||||
assembler->Int32LessThan(start_from_var.value(), int32_zero),
|
||||
&if_negative, &if_positive);
|
||||
|
||||
assembler->Bind(&if_positive);
|
||||
{
|
||||
index_var.Bind(start_from_var.value());
|
||||
assembler->Goto(&done);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_negative);
|
||||
{
|
||||
index_var.Bind(
|
||||
assembler->Int32Add(len_var.value(), start_from_var.value()));
|
||||
assembler->Branch(
|
||||
assembler->Int32LessThan(index_var.value(), int32_zero),
|
||||
&init_k_zero, &done);
|
||||
}
|
||||
|
||||
assembler->Bind(&init_k_zero);
|
||||
{
|
||||
index_var.Bind(int32_zero);
|
||||
assembler->Goto(&done);
|
||||
}
|
||||
|
||||
assembler->Bind(&done);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t kElementsKind[] = {
|
||||
FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS,
|
||||
FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS,
|
||||
};
|
||||
|
||||
Label if_smiorobjects(assembler), if_packed_doubles(assembler),
|
||||
if_holey_doubles(assembler);
|
||||
Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects,
|
||||
&if_smiorobjects, &if_smiorobjects,
|
||||
&if_packed_doubles, &if_holey_doubles};
|
||||
|
||||
Node* map = assembler->LoadMap(array);
|
||||
Node* bit_field2 = assembler->LoadMapBitField2(map);
|
||||
Node* elements_kind =
|
||||
assembler->BitFieldDecode<Map::ElementsKindBits>(bit_field2);
|
||||
Node* elements = assembler->LoadElements(array);
|
||||
assembler->Switch(elements_kind, &return_false, kElementsKind,
|
||||
element_kind_handlers, arraysize(kElementsKind));
|
||||
|
||||
assembler->Bind(&if_smiorobjects);
|
||||
{
|
||||
Variable search_num(assembler, MachineRepresentation::kFloat64);
|
||||
Label ident_loop(assembler, &index_var),
|
||||
heap_num_loop(assembler, &search_num),
|
||||
string_loop(assembler, &index_var), simd_loop(assembler),
|
||||
undef_loop(assembler, &index_var), not_smi(assembler),
|
||||
not_heap_num(assembler);
|
||||
|
||||
assembler->GotoUnless(assembler->WordIsSmi(search_element), ¬_smi);
|
||||
search_num.Bind(assembler->SmiToFloat64(search_element));
|
||||
assembler->Goto(&heap_num_loop);
|
||||
|
||||
assembler->Bind(¬_smi);
|
||||
assembler->GotoIf(assembler->WordEqual(search_element, undefined),
|
||||
&undef_loop);
|
||||
Node* map = assembler->LoadMap(search_element);
|
||||
assembler->GotoIf(assembler->WordNotEqual(map, heap_number_map),
|
||||
¬_heap_num);
|
||||
search_num.Bind(assembler->LoadHeapNumberValue(search_element));
|
||||
assembler->Goto(&heap_num_loop);
|
||||
|
||||
assembler->Bind(¬_heap_num);
|
||||
Node* search_type = assembler->LoadMapInstanceType(map);
|
||||
assembler->GotoIf(
|
||||
assembler->Int32LessThan(
|
||||
search_type, assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
|
||||
&string_loop);
|
||||
assembler->GotoIf(
|
||||
assembler->WordEqual(search_type,
|
||||
assembler->Int32Constant(SIMD128_VALUE_TYPE)),
|
||||
&simd_loop);
|
||||
assembler->Goto(&ident_loop);
|
||||
|
||||
assembler->Bind(&ident_loop);
|
||||
{
|
||||
assembler->GotoUnless(
|
||||
assembler->Int32LessThan(index_var.value(), len_var.value()),
|
||||
&return_false);
|
||||
Node* element_k =
|
||||
assembler->LoadFixedArrayElement(elements, index_var.value());
|
||||
assembler->GotoIf(assembler->WordEqual(element_k, search_element),
|
||||
&return_true);
|
||||
|
||||
index_var.Bind(assembler->Int32Add(index_var.value(), int32_one));
|
||||
assembler->Goto(&ident_loop);
|
||||
}
|
||||
|
||||
assembler->Bind(&undef_loop);
|
||||
{
|
||||
assembler->GotoUnless(
|
||||
assembler->Int32LessThan(index_var.value(), len_var.value()),
|
||||
&return_false);
|
||||
Node* element_k =
|
||||
assembler->LoadFixedArrayElement(elements, index_var.value());
|
||||
assembler->GotoIf(assembler->WordEqual(element_k, undefined),
|
||||
&return_true);
|
||||
assembler->GotoIf(assembler->WordEqual(element_k, the_hole),
|
||||
&return_true);
|
||||
|
||||
index_var.Bind(assembler->Int32Add(index_var.value(), int32_one));
|
||||
assembler->Goto(&undef_loop);
|
||||
}
|
||||
|
||||
assembler->Bind(&heap_num_loop);
|
||||
{
|
||||
Label nan_loop(assembler, &index_var),
|
||||
not_nan_loop(assembler, &index_var);
|
||||
assembler->BranchIfFloat64IsNaN(search_num.value(), &nan_loop,
|
||||
¬_nan_loop);
|
||||
|
||||
assembler->Bind(¬_nan_loop);
|
||||
{
|
||||
Label continue_loop(assembler), not_smi(assembler);
|
||||
assembler->GotoUnless(
|
||||
assembler->Int32LessThan(index_var.value(), len_var.value()),
|
||||
&return_false);
|
||||
Node* element_k =
|
||||
assembler->LoadFixedArrayElement(elements, index_var.value());
|
||||
assembler->GotoUnless(assembler->WordIsSmi(element_k), ¬_smi);
|
||||
assembler->Branch(
|
||||
assembler->Float64Equal(search_num.value(),
|
||||
assembler->SmiToFloat64(element_k)),
|
||||
&return_true, &continue_loop);
|
||||
|
||||
assembler->Bind(¬_smi);
|
||||
assembler->GotoIf(assembler->WordNotEqual(assembler->LoadMap(element_k),
|
||||
heap_number_map),
|
||||
&continue_loop);
|
||||
assembler->BranchIfFloat64Equal(
|
||||
search_num.value(), assembler->LoadHeapNumberValue(element_k),
|
||||
&return_true, &continue_loop);
|
||||
|
||||
assembler->Bind(&continue_loop);
|
||||
index_var.Bind(assembler->Int32Add(index_var.value(), int32_one));
|
||||
assembler->Goto(¬_nan_loop);
|
||||
}
|
||||
|
||||
assembler->Bind(&nan_loop);
|
||||
{
|
||||
Label continue_loop(assembler);
|
||||
assembler->GotoUnless(
|
||||
assembler->Int32LessThan(index_var.value(), len_var.value()),
|
||||
&return_false);
|
||||
Node* element_k =
|
||||
assembler->LoadFixedArrayElement(elements, index_var.value());
|
||||
assembler->GotoIf(assembler->WordIsSmi(element_k), &continue_loop);
|
||||
assembler->GotoIf(assembler->WordNotEqual(assembler->LoadMap(element_k),
|
||||
heap_number_map),
|
||||
&continue_loop);
|
||||
assembler->BranchIfFloat64IsNaN(
|
||||
assembler->LoadHeapNumberValue(element_k), &return_true,
|
||||
&continue_loop);
|
||||
|
||||
assembler->Bind(&continue_loop);
|
||||
index_var.Bind(assembler->Int32Add(index_var.value(), int32_one));
|
||||
assembler->Goto(&nan_loop);
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&string_loop);
|
||||
{
|
||||
Label continue_loop(assembler);
|
||||
assembler->GotoUnless(
|
||||
assembler->Int32LessThan(index_var.value(), len_var.value()),
|
||||
&return_false);
|
||||
Node* element_k =
|
||||
assembler->LoadFixedArrayElement(elements, index_var.value());
|
||||
assembler->GotoIf(assembler->WordIsSmi(element_k), &continue_loop);
|
||||
assembler->GotoUnless(assembler->Int32LessThan(
|
||||
assembler->LoadMapInstanceType(element_k),
|
||||
assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
|
||||
&continue_loop);
|
||||
|
||||
// TODO(bmeurer): Consider inlining the StringEqual logic here.
|
||||
Callable callable = CodeFactory::StringEqual(assembler->isolate());
|
||||
Node* result =
|
||||
assembler->CallStub(callable, context, search_element, element_k);
|
||||
assembler->Branch(
|
||||
assembler->WordEqual(assembler->BooleanConstant(true), result),
|
||||
&return_true, &continue_loop);
|
||||
|
||||
assembler->Bind(&continue_loop);
|
||||
index_var.Bind(assembler->Int32Add(index_var.value(), int32_one));
|
||||
assembler->Goto(&string_loop);
|
||||
}
|
||||
|
||||
assembler->Bind(&simd_loop);
|
||||
{
|
||||
Label continue_loop(assembler, &index_var),
|
||||
loop_body(assembler, &index_var);
|
||||
Node* map = assembler->LoadMap(search_element);
|
||||
|
||||
assembler->Goto(&loop_body);
|
||||
assembler->Bind(&loop_body);
|
||||
assembler->GotoUnless(
|
||||
assembler->Int32LessThan(index_var.value(), len_var.value()),
|
||||
&return_false);
|
||||
|
||||
Node* element_k =
|
||||
assembler->LoadFixedArrayElement(elements, index_var.value());
|
||||
assembler->GotoIf(assembler->WordIsSmi(element_k), &continue_loop);
|
||||
|
||||
Node* map_k = assembler->LoadMap(element_k);
|
||||
assembler->BranchIfSimd128Equal(search_element, map, element_k, map_k,
|
||||
&return_true, &continue_loop);
|
||||
|
||||
assembler->Bind(&continue_loop);
|
||||
index_var.Bind(assembler->Int32Add(index_var.value(), int32_one));
|
||||
assembler->Goto(&loop_body);
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&if_packed_doubles);
|
||||
{
|
||||
Label nan_loop(assembler, &index_var), not_nan_loop(assembler, &index_var),
|
||||
hole_loop(assembler, &index_var), search_notnan(assembler);
|
||||
Variable search_num(assembler, MachineRepresentation::kFloat64);
|
||||
|
||||
assembler->GotoUnless(assembler->WordIsSmi(search_element), &search_notnan);
|
||||
search_num.Bind(assembler->SmiToFloat64(search_element));
|
||||
assembler->Goto(¬_nan_loop);
|
||||
|
||||
assembler->Bind(&search_notnan);
|
||||
assembler->GotoIf(assembler->WordNotEqual(
|
||||
assembler->LoadMap(search_element), heap_number_map),
|
||||
&return_false);
|
||||
|
||||
search_num.Bind(assembler->LoadHeapNumberValue(search_element));
|
||||
|
||||
assembler->BranchIfFloat64IsNaN(search_num.value(), &nan_loop,
|
||||
¬_nan_loop);
|
||||
|
||||
// Search for HeapNumber
|
||||
assembler->Bind(¬_nan_loop);
|
||||
{
|
||||
Label continue_loop(assembler);
|
||||
assembler->GotoUnless(
|
||||
assembler->Int32LessThan(index_var.value(), len_var.value()),
|
||||
&return_false);
|
||||
Node* element_k = assembler->LoadFixedDoubleArrayElement(
|
||||
elements, index_var.value(), MachineType::Float64());
|
||||
assembler->BranchIfFloat64Equal(element_k, search_num.value(),
|
||||
&return_true, &continue_loop);
|
||||
assembler->Bind(&continue_loop);
|
||||
index_var.Bind(assembler->Int32Add(index_var.value(), int32_one));
|
||||
assembler->Goto(¬_nan_loop);
|
||||
}
|
||||
|
||||
// Search for NaN
|
||||
assembler->Bind(&nan_loop);
|
||||
{
|
||||
Label continue_loop(assembler);
|
||||
assembler->GotoUnless(
|
||||
assembler->Int32LessThan(index_var.value(), len_var.value()),
|
||||
&return_false);
|
||||
Node* element_k = assembler->LoadFixedDoubleArrayElement(
|
||||
elements, index_var.value(), MachineType::Float64());
|
||||
assembler->BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop);
|
||||
assembler->Bind(&continue_loop);
|
||||
index_var.Bind(assembler->Int32Add(index_var.value(), int32_one));
|
||||
assembler->Goto(&nan_loop);
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&if_holey_doubles);
|
||||
{
|
||||
Label nan_loop(assembler, &index_var), not_nan_loop(assembler, &index_var),
|
||||
hole_loop(assembler, &index_var), search_notnan(assembler);
|
||||
Variable search_num(assembler, MachineRepresentation::kFloat64);
|
||||
|
||||
assembler->GotoUnless(assembler->WordIsSmi(search_element), &search_notnan);
|
||||
search_num.Bind(assembler->SmiToFloat64(search_element));
|
||||
assembler->Goto(¬_nan_loop);
|
||||
|
||||
assembler->Bind(&search_notnan);
|
||||
assembler->GotoIf(assembler->WordEqual(search_element, undefined),
|
||||
&hole_loop);
|
||||
assembler->GotoIf(assembler->WordNotEqual(
|
||||
assembler->LoadMap(search_element), heap_number_map),
|
||||
&return_false);
|
||||
|
||||
search_num.Bind(assembler->LoadHeapNumberValue(search_element));
|
||||
|
||||
assembler->BranchIfFloat64IsNaN(search_num.value(), &nan_loop,
|
||||
¬_nan_loop);
|
||||
|
||||
// Search for HeapNumber
|
||||
assembler->Bind(¬_nan_loop);
|
||||
{
|
||||
Label continue_loop(assembler);
|
||||
assembler->GotoUnless(
|
||||
assembler->Int32LessThan(index_var.value(), len_var.value()),
|
||||
&return_false);
|
||||
|
||||
if (kPointerSize == kDoubleSize) {
|
||||
Node* element = assembler->LoadFixedDoubleArrayElement(
|
||||
elements, index_var.value(), MachineType::Uint64());
|
||||
Node* the_hole = assembler->Int64Constant(kHoleNanInt64);
|
||||
assembler->GotoIf(assembler->Word64Equal(element, the_hole),
|
||||
&continue_loop);
|
||||
} else {
|
||||
Node* element_upper = assembler->LoadFixedDoubleArrayElement(
|
||||
elements, index_var.value(), MachineType::Uint32(),
|
||||
kIeeeDoubleExponentWordOffset);
|
||||
assembler->GotoIf(
|
||||
assembler->Word32Equal(element_upper,
|
||||
assembler->Int32Constant(kHoleNanUpper32)),
|
||||
&continue_loop);
|
||||
}
|
||||
|
||||
Node* element_k = assembler->LoadFixedDoubleArrayElement(
|
||||
elements, index_var.value(), MachineType::Float64());
|
||||
assembler->BranchIfFloat64Equal(element_k, search_num.value(),
|
||||
&return_true, &continue_loop);
|
||||
assembler->Bind(&continue_loop);
|
||||
index_var.Bind(assembler->Int32Add(index_var.value(), int32_one));
|
||||
assembler->Goto(¬_nan_loop);
|
||||
}
|
||||
|
||||
// Search for NaN
|
||||
assembler->Bind(&nan_loop);
|
||||
{
|
||||
Label continue_loop(assembler);
|
||||
assembler->GotoUnless(
|
||||
assembler->Int32LessThan(index_var.value(), len_var.value()),
|
||||
&return_false);
|
||||
|
||||
if (kPointerSize == kDoubleSize) {
|
||||
Node* element = assembler->LoadFixedDoubleArrayElement(
|
||||
elements, index_var.value(), MachineType::Uint64());
|
||||
Node* the_hole = assembler->Int64Constant(kHoleNanInt64);
|
||||
assembler->GotoIf(assembler->Word64Equal(element, the_hole),
|
||||
&continue_loop);
|
||||
} else {
|
||||
Node* element_upper = assembler->LoadFixedDoubleArrayElement(
|
||||
elements, index_var.value(), MachineType::Uint32(),
|
||||
kIeeeDoubleExponentWordOffset);
|
||||
assembler->GotoIf(
|
||||
assembler->Word32Equal(element_upper,
|
||||
assembler->Int32Constant(kHoleNanUpper32)),
|
||||
&continue_loop);
|
||||
}
|
||||
|
||||
Node* element_k = assembler->LoadFixedDoubleArrayElement(
|
||||
elements, index_var.value(), MachineType::Float64());
|
||||
assembler->BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop);
|
||||
assembler->Bind(&continue_loop);
|
||||
index_var.Bind(assembler->Int32Add(index_var.value(), int32_one));
|
||||
assembler->Goto(&nan_loop);
|
||||
}
|
||||
|
||||
// Search for the Hole
|
||||
assembler->Bind(&hole_loop);
|
||||
{
|
||||
assembler->GotoUnless(
|
||||
assembler->Int32LessThan(index_var.value(), len_var.value()),
|
||||
&return_false);
|
||||
|
||||
if (kPointerSize == kDoubleSize) {
|
||||
Node* element = assembler->LoadFixedDoubleArrayElement(
|
||||
elements, index_var.value(), MachineType::Uint64());
|
||||
Node* the_hole = assembler->Int64Constant(kHoleNanInt64);
|
||||
assembler->GotoIf(assembler->Word64Equal(element, the_hole),
|
||||
&return_true);
|
||||
} else {
|
||||
Node* element_upper = assembler->LoadFixedDoubleArrayElement(
|
||||
elements, index_var.value(), MachineType::Uint32(),
|
||||
kIeeeDoubleExponentWordOffset);
|
||||
assembler->GotoIf(
|
||||
assembler->Word32Equal(element_upper,
|
||||
assembler->Int32Constant(kHoleNanUpper32)),
|
||||
&return_true);
|
||||
}
|
||||
|
||||
index_var.Bind(assembler->Int32Add(index_var.value(), int32_one));
|
||||
assembler->Goto(&hole_loop);
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&return_true);
|
||||
assembler->Return(assembler->BooleanConstant(true));
|
||||
|
||||
assembler->Bind(&return_false);
|
||||
assembler->Return(assembler->BooleanConstant(false));
|
||||
|
||||
assembler->Bind(&call_runtime);
|
||||
assembler->Return(assembler->CallRuntime(Runtime::kArrayIncludes_Slow,
|
||||
context, array, search_element,
|
||||
start_from));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -191,8 +191,6 @@ namespace internal {
|
||||
CPP(ArrayConcat) \
|
||||
/* ES6 section 22.1.2.2 Array.isArray */ \
|
||||
TFJ(ArrayIsArray, 2) \
|
||||
/* ES7 #sec-array.prototype.includes */ \
|
||||
TFJ(ArrayIncludes, 3) \
|
||||
CPP(ArrayPop) \
|
||||
CPP(ArrayPush) \
|
||||
CPP(ArrayShift) \
|
||||
|
@ -471,216 +471,6 @@ Node* CodeStubAssembler::WordIsPositiveSmi(Node* a) {
|
||||
IntPtrConstant(0));
|
||||
}
|
||||
|
||||
void CodeStubAssembler::BranchIfSameValueZero(Node* a, Node* b, Node* context,
|
||||
Label* if_true, Label* if_false) {
|
||||
Node* number_map = HeapNumberMapConstant();
|
||||
Label a_isnumber(this), a_isnotnumber(this), b_isnumber(this), a_isnan(this),
|
||||
float_not_equal(this);
|
||||
// If register A and register B are identical, goto `if_true`
|
||||
GotoIf(WordEqual(a, b), if_true);
|
||||
// If either register A or B are Smis, goto `if_false`
|
||||
GotoIf(Word32Or(WordIsSmi(a), WordIsSmi(b)), if_false);
|
||||
// GotoIf(WordIsSmi(b), if_false);
|
||||
|
||||
Node* a_map = LoadMap(a);
|
||||
Node* b_map = LoadMap(b);
|
||||
Branch(WordEqual(a_map, number_map), &a_isnumber, &a_isnotnumber);
|
||||
|
||||
// If both register A and B are HeapNumbers, return true if they are equal,
|
||||
// or if both are NaN
|
||||
Bind(&a_isnumber);
|
||||
{
|
||||
Branch(WordEqual(b_map, number_map), &b_isnumber, if_false);
|
||||
|
||||
Bind(&b_isnumber);
|
||||
Node* a_value = LoadHeapNumberValue(a);
|
||||
Node* b_value = LoadHeapNumberValue(b);
|
||||
BranchIfFloat64Equal(a_value, b_value, if_true, &float_not_equal);
|
||||
|
||||
Bind(&float_not_equal);
|
||||
BranchIfFloat64IsNaN(a_value, &a_isnan, if_false);
|
||||
|
||||
Bind(&a_isnan);
|
||||
BranchIfFloat64IsNaN(a_value, if_true, if_false);
|
||||
}
|
||||
|
||||
Bind(&a_isnotnumber);
|
||||
{
|
||||
Label a_isstring(this), a_isnotstring(this);
|
||||
Node* a_instance_type = LoadMapInstanceType(a_map);
|
||||
|
||||
Branch(Int32LessThan(a_instance_type, Int32Constant(FIRST_NONSTRING_TYPE)),
|
||||
&a_isstring, &a_isnotstring);
|
||||
|
||||
Bind(&a_isstring);
|
||||
{
|
||||
Label b_isstring(this), b_isnotstring(this);
|
||||
Node* b_instance_type = LoadInstanceType(b_map);
|
||||
|
||||
Branch(
|
||||
Int32LessThan(b_instance_type, Int32Constant(FIRST_NONSTRING_TYPE)),
|
||||
&b_isstring, if_false);
|
||||
|
||||
Bind(&b_isstring);
|
||||
{
|
||||
Callable callable = CodeFactory::StringEqual(isolate());
|
||||
Node* result = CallStub(callable, context, a, b);
|
||||
Branch(WordEqual(BooleanConstant(true), result), if_true, if_false);
|
||||
}
|
||||
}
|
||||
|
||||
Bind(&a_isnotstring);
|
||||
{
|
||||
// Check if {lhs} is a Simd128Value.
|
||||
Label a_issimd128value(this);
|
||||
Branch(Word32Equal(a_instance_type, Int32Constant(SIMD128_VALUE_TYPE)),
|
||||
&a_issimd128value, if_false);
|
||||
|
||||
Bind(&a_issimd128value);
|
||||
{
|
||||
// Load the map of {rhs}.
|
||||
BranchIfSimd128Equal(a, a_map, b, b_map, if_true, if_false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CodeStubAssembler::BranchIfSimd128Equal(Node* lhs, Node* lhs_map,
|
||||
Node* rhs, Node* rhs_map,
|
||||
Label* if_equal,
|
||||
Label* if_notequal) {
|
||||
Label if_mapsame(this), if_mapnotsame(this);
|
||||
Branch(WordEqual(lhs_map, rhs_map), &if_mapsame, &if_mapnotsame);
|
||||
|
||||
Bind(&if_mapsame);
|
||||
{
|
||||
// Both {lhs} and {rhs} are Simd128Values with the same map, need special
|
||||
// handling for Float32x4 because of NaN comparisons.
|
||||
Label if_float32x4(this), if_notfloat32x4(this);
|
||||
Node* float32x4_map = HeapConstant(factory()->float32x4_map());
|
||||
Branch(WordEqual(lhs_map, float32x4_map), &if_float32x4, &if_notfloat32x4);
|
||||
|
||||
Bind(&if_float32x4);
|
||||
{
|
||||
// Both {lhs} and {rhs} are Float32x4, compare the lanes individually
|
||||
// using a floating point comparison.
|
||||
for (int offset = Float32x4::kValueOffset - kHeapObjectTag;
|
||||
offset < Float32x4::kSize - kHeapObjectTag;
|
||||
offset += sizeof(float)) {
|
||||
// Load the floating point values for {lhs} and {rhs}.
|
||||
Node* lhs_value =
|
||||
Load(MachineType::Float32(), lhs, IntPtrConstant(offset));
|
||||
Node* rhs_value =
|
||||
Load(MachineType::Float32(), rhs, IntPtrConstant(offset));
|
||||
|
||||
// Perform a floating point comparison.
|
||||
Label if_valueequal(this), if_valuenotequal(this);
|
||||
Branch(Float32Equal(lhs_value, rhs_value), &if_valueequal,
|
||||
&if_valuenotequal);
|
||||
Bind(&if_valuenotequal);
|
||||
Goto(if_notequal);
|
||||
Bind(&if_valueequal);
|
||||
}
|
||||
|
||||
// All 4 lanes match, {lhs} and {rhs} considered equal.
|
||||
Goto(if_equal);
|
||||
}
|
||||
|
||||
Bind(&if_notfloat32x4);
|
||||
{
|
||||
// For other Simd128Values we just perform a bitwise comparison.
|
||||
for (int offset = Simd128Value::kValueOffset - kHeapObjectTag;
|
||||
offset < Simd128Value::kSize - kHeapObjectTag;
|
||||
offset += kPointerSize) {
|
||||
// Load the word values for {lhs} and {rhs}.
|
||||
Node* lhs_value =
|
||||
Load(MachineType::Pointer(), lhs, IntPtrConstant(offset));
|
||||
Node* rhs_value =
|
||||
Load(MachineType::Pointer(), rhs, IntPtrConstant(offset));
|
||||
|
||||
// Perform a bitwise word-comparison.
|
||||
Label if_valueequal(this), if_valuenotequal(this);
|
||||
Branch(WordEqual(lhs_value, rhs_value), &if_valueequal,
|
||||
&if_valuenotequal);
|
||||
Bind(&if_valuenotequal);
|
||||
Goto(if_notequal);
|
||||
Bind(&if_valueequal);
|
||||
}
|
||||
|
||||
// Bitwise comparison succeeded, {lhs} and {rhs} considered equal.
|
||||
Goto(if_equal);
|
||||
}
|
||||
}
|
||||
|
||||
Bind(&if_mapnotsame);
|
||||
Goto(if_notequal);
|
||||
}
|
||||
|
||||
void CodeStubAssembler::BranchIfFastJSArray(Node* object, Node* context,
|
||||
Label* if_true, Label* if_false) {
|
||||
Node* int32_zero = Int32Constant(0);
|
||||
Node* int32_one = Int32Constant(1);
|
||||
|
||||
Node* empty_elements = LoadRoot(Heap::kEmptyFixedArrayRootIndex);
|
||||
|
||||
Variable last_map(this, MachineRepresentation::kTagged);
|
||||
Label check_prototype(this);
|
||||
|
||||
// Bailout if Smi
|
||||
GotoIf(WordIsSmi(object), if_false);
|
||||
|
||||
Node* map = LoadMap(object);
|
||||
last_map.Bind(map);
|
||||
|
||||
// Bailout if instance type is not JS_ARRAY_TYPE
|
||||
GotoIf(WordNotEqual(LoadMapInstanceType(map), Int32Constant(JS_ARRAY_TYPE)),
|
||||
if_false);
|
||||
|
||||
Node* bit_field2 = LoadMapBitField2(map);
|
||||
Node* elements_kind = BitFieldDecode<Map::ElementsKindBits>(bit_field2);
|
||||
|
||||
// Bailout if slow receiver elements
|
||||
GotoIf(
|
||||
Int32GreaterThan(elements_kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)),
|
||||
if_false);
|
||||
|
||||
STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == (FAST_SMI_ELEMENTS | 1));
|
||||
STATIC_ASSERT(FAST_HOLEY_ELEMENTS == (FAST_ELEMENTS | 1));
|
||||
STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == (FAST_DOUBLE_ELEMENTS | 1));
|
||||
|
||||
// Check prototype chain if receiver does not have packed elements
|
||||
Node* holey_elements = Word32And(elements_kind, int32_one);
|
||||
Branch(Word32Equal(holey_elements, int32_zero), if_true, &check_prototype);
|
||||
|
||||
Bind(&check_prototype);
|
||||
{
|
||||
Label loop_body(this, &last_map);
|
||||
Goto(&loop_body);
|
||||
Bind(&loop_body);
|
||||
Node* current_map = last_map.value();
|
||||
Node* proto = LoadObjectField(current_map, Map::kPrototypeOffset);
|
||||
|
||||
// End loop
|
||||
GotoIf(WordEqual(proto, NullConstant()), if_true);
|
||||
|
||||
// ASSERT: proto->IsHeapObject()
|
||||
Node* proto_map = LoadMap(proto);
|
||||
|
||||
// Bailout if a Proxy, API Object, or JSValue wrapper found in prototype
|
||||
// Because of this bailout, it's not necessary to check for interceptors or
|
||||
// access checks on the prototype chain.
|
||||
GotoIf(Int32LessThanOrEqual(LoadMapInstanceType(proto_map),
|
||||
Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
|
||||
if_false);
|
||||
|
||||
// Bailout if prototype contains non-empty elements
|
||||
GotoUnless(WordEqual(LoadElements(proto), empty_elements), if_false);
|
||||
|
||||
last_map.Bind(proto_map);
|
||||
Goto(&loop_body);
|
||||
}
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::AllocateRawUnaligned(Node* size_in_bytes,
|
||||
AllocationFlags flags,
|
||||
Node* top_address,
|
||||
|
@ -124,22 +124,6 @@ class CodeStubAssembler : public compiler::CodeAssembler {
|
||||
void BranchIfToBooleanIsTrue(compiler::Node* value, Label* if_true,
|
||||
Label* if_false);
|
||||
|
||||
void BranchIfSimd128Equal(compiler::Node* lhs, compiler::Node* lhs_map,
|
||||
compiler::Node* rhs, compiler::Node* rhs_map,
|
||||
Label* if_equal, Label* if_notequal);
|
||||
void BranchIfSimd128Equal(compiler::Node* lhs, compiler::Node* rhs,
|
||||
Label* if_equal, Label* if_notequal) {
|
||||
BranchIfSimd128Equal(lhs, LoadMap(lhs), rhs, LoadMap(rhs), if_equal,
|
||||
if_notequal);
|
||||
}
|
||||
|
||||
void BranchIfSameValueZero(compiler::Node* a, compiler::Node* b,
|
||||
compiler::Node* context, Label* if_true,
|
||||
Label* if_false);
|
||||
|
||||
void BranchIfFastJSArray(compiler::Node* object, compiler::Node* context,
|
||||
Label* if_true, Label* if_false);
|
||||
|
||||
// Load value from current frame by given offset in bytes.
|
||||
compiler::Node* LoadFromFrame(int offset,
|
||||
MachineType rep = MachineType::AnyTagged());
|
||||
|
@ -2342,8 +2342,78 @@ void GenerateEqual_Simd128Value_HeapObject(
|
||||
CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* lhs_map,
|
||||
compiler::Node* rhs, compiler::Node* rhs_map,
|
||||
CodeStubAssembler::Label* if_equal, CodeStubAssembler::Label* if_notequal) {
|
||||
assembler->BranchIfSimd128Equal(lhs, lhs_map, rhs, rhs_map, if_equal,
|
||||
if_notequal);
|
||||
typedef CodeStubAssembler::Label Label;
|
||||
typedef compiler::Node Node;
|
||||
|
||||
// Check if {lhs} and {rhs} have the same map.
|
||||
Label if_mapsame(assembler), if_mapnotsame(assembler);
|
||||
assembler->Branch(assembler->WordEqual(lhs_map, rhs_map), &if_mapsame,
|
||||
&if_mapnotsame);
|
||||
|
||||
assembler->Bind(&if_mapsame);
|
||||
{
|
||||
// Both {lhs} and {rhs} are Simd128Values with the same map, need special
|
||||
// handling for Float32x4 because of NaN comparisons.
|
||||
Label if_float32x4(assembler), if_notfloat32x4(assembler);
|
||||
Node* float32x4_map =
|
||||
assembler->HeapConstant(assembler->factory()->float32x4_map());
|
||||
assembler->Branch(assembler->WordEqual(lhs_map, float32x4_map),
|
||||
&if_float32x4, &if_notfloat32x4);
|
||||
|
||||
assembler->Bind(&if_float32x4);
|
||||
{
|
||||
// Both {lhs} and {rhs} are Float32x4, compare the lanes individually
|
||||
// using a floating point comparison.
|
||||
for (int offset = Float32x4::kValueOffset - kHeapObjectTag;
|
||||
offset < Float32x4::kSize - kHeapObjectTag;
|
||||
offset += sizeof(float)) {
|
||||
// Load the floating point values for {lhs} and {rhs}.
|
||||
Node* lhs_value = assembler->Load(MachineType::Float32(), lhs,
|
||||
assembler->IntPtrConstant(offset));
|
||||
Node* rhs_value = assembler->Load(MachineType::Float32(), rhs,
|
||||
assembler->IntPtrConstant(offset));
|
||||
|
||||
// Perform a floating point comparison.
|
||||
Label if_valueequal(assembler), if_valuenotequal(assembler);
|
||||
assembler->Branch(assembler->Float32Equal(lhs_value, rhs_value),
|
||||
&if_valueequal, &if_valuenotequal);
|
||||
assembler->Bind(&if_valuenotequal);
|
||||
assembler->Goto(if_notequal);
|
||||
assembler->Bind(&if_valueequal);
|
||||
}
|
||||
|
||||
// All 4 lanes match, {lhs} and {rhs} considered equal.
|
||||
assembler->Goto(if_equal);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_notfloat32x4);
|
||||
{
|
||||
// For other Simd128Values we just perform a bitwise comparison.
|
||||
for (int offset = Simd128Value::kValueOffset - kHeapObjectTag;
|
||||
offset < Simd128Value::kSize - kHeapObjectTag;
|
||||
offset += kPointerSize) {
|
||||
// Load the word values for {lhs} and {rhs}.
|
||||
Node* lhs_value = assembler->Load(MachineType::Pointer(), lhs,
|
||||
assembler->IntPtrConstant(offset));
|
||||
Node* rhs_value = assembler->Load(MachineType::Pointer(), rhs,
|
||||
assembler->IntPtrConstant(offset));
|
||||
|
||||
// Perform a bitwise word-comparison.
|
||||
Label if_valueequal(assembler), if_valuenotequal(assembler);
|
||||
assembler->Branch(assembler->WordEqual(lhs_value, rhs_value),
|
||||
&if_valueequal, &if_valuenotequal);
|
||||
assembler->Bind(&if_valuenotequal);
|
||||
assembler->Goto(if_notequal);
|
||||
assembler->Bind(&if_valueequal);
|
||||
}
|
||||
|
||||
// Bitwise comparison succeeded, {lhs} and {rhs} considered equal.
|
||||
assembler->Goto(if_equal);
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&if_mapnotsame);
|
||||
assembler->Goto(if_notequal);
|
||||
}
|
||||
|
||||
// ES6 section 7.2.12 Abstract Equality Comparison
|
||||
|
@ -869,7 +869,7 @@ void CodeAssembler::Branch(Node* condition, CodeAssembler::Label* true_label,
|
||||
}
|
||||
|
||||
void CodeAssembler::Switch(Node* index, Label* default_label,
|
||||
const int32_t* case_values, Label** case_labels,
|
||||
int32_t* case_values, Label** case_labels,
|
||||
size_t case_count) {
|
||||
RawMachineLabel** labels =
|
||||
new (zone()->New(sizeof(RawMachineLabel*) * case_count))
|
||||
|
@ -246,7 +246,7 @@ class CodeAssembler {
|
||||
void GotoUnless(Node* condition, Label* false_label);
|
||||
void Branch(Node* condition, Label* true_label, Label* false_label);
|
||||
|
||||
void Switch(Node* index, Label* default_label, const int32_t* case_values,
|
||||
void Switch(Node* index, Label* default_label, int32_t* case_values,
|
||||
Label** case_labels, size_t case_count);
|
||||
|
||||
Node* Select(Node* condition, Node* true_value, Node* false_value,
|
||||
|
@ -85,8 +85,9 @@ void RawMachineAssembler::Branch(Node* condition, RawMachineLabel* true_val,
|
||||
current_block_ = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void RawMachineAssembler::Switch(Node* index, RawMachineLabel* default_label,
|
||||
const int32_t* case_values,
|
||||
int32_t* case_values,
|
||||
RawMachineLabel** case_labels,
|
||||
size_t case_count) {
|
||||
DCHECK_NE(schedule()->end(), current_block_);
|
||||
|
@ -754,9 +754,8 @@ class RawMachineAssembler {
|
||||
void Goto(RawMachineLabel* label);
|
||||
void Branch(Node* condition, RawMachineLabel* true_val,
|
||||
RawMachineLabel* false_val);
|
||||
void Switch(Node* index, RawMachineLabel* default_label,
|
||||
const int32_t* case_values, RawMachineLabel** case_labels,
|
||||
size_t case_count);
|
||||
void Switch(Node* index, RawMachineLabel* default_label, int32_t* case_values,
|
||||
RawMachineLabel** case_labels, size_t case_count);
|
||||
void Return(Node* value);
|
||||
void Return(Node* v1, Node* v2);
|
||||
void Return(Node* v1, Node* v2, Node* v3);
|
||||
|
374
src/elements.cc
374
src/elements.cc
@ -468,27 +468,6 @@ static void SortIndices(
|
||||
}
|
||||
}
|
||||
|
||||
static Maybe<bool> IncludesValueSlowPath(Isolate* isolate,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<Object> value,
|
||||
uint32_t start_from, uint32_t length) {
|
||||
bool search_for_hole = value->IsUndefined(isolate);
|
||||
for (uint32_t k = start_from; k < length; ++k) {
|
||||
LookupIterator it(isolate, receiver, k);
|
||||
if (!it.IsFound()) {
|
||||
if (search_for_hole) return Just(true);
|
||||
continue;
|
||||
}
|
||||
Handle<Object> element_k;
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
|
||||
Object::GetProperty(&it), Nothing<bool>());
|
||||
|
||||
if (value->SameValueZero(*element_k)) return Just(true);
|
||||
}
|
||||
|
||||
return Just(false);
|
||||
}
|
||||
|
||||
// Base class for element handler implementations. Contains the
|
||||
// the common logic for objects with different ElementsKinds.
|
||||
// Subclasses must specialize method for which the element
|
||||
@ -1105,20 +1084,6 @@ class ElementsAccessorBase : public ElementsAccessor {
|
||||
return Subclass::GetCapacityImpl(holder, backing_store);
|
||||
}
|
||||
|
||||
static Maybe<bool> IncludesValueImpl(Isolate* isolate,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<Object> value,
|
||||
uint32_t start_from, uint32_t length) {
|
||||
return IncludesValueSlowPath(isolate, receiver, value, start_from, length);
|
||||
}
|
||||
|
||||
Maybe<bool> IncludesValue(Isolate* isolate, Handle<JSObject> receiver,
|
||||
Handle<Object> value, uint32_t start_from,
|
||||
uint32_t length) final {
|
||||
return Subclass::IncludesValueImpl(isolate, receiver, value, start_from,
|
||||
length);
|
||||
}
|
||||
|
||||
static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
|
||||
uint32_t entry) {
|
||||
return entry;
|
||||
@ -1455,102 +1420,6 @@ class DictionaryElementsAccessor
|
||||
accumulator->AddKey(value, convert);
|
||||
}
|
||||
}
|
||||
|
||||
static bool IncludesValueFastPath(Isolate* isolate, Handle<JSObject> receiver,
|
||||
Handle<Object> value, uint32_t start_from,
|
||||
uint32_t length, Maybe<bool>* result) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
SeededNumberDictionary* dictionary =
|
||||
SeededNumberDictionary::cast(receiver->elements());
|
||||
int capacity = dictionary->Capacity();
|
||||
Object* the_hole = isolate->heap()->the_hole_value();
|
||||
Object* undefined = isolate->heap()->undefined_value();
|
||||
|
||||
// Scan for accessor properties. If accessors are present, then elements
|
||||
// must be accessed in order via the slow path.
|
||||
bool found = false;
|
||||
for (int i = 0; i < capacity; ++i) {
|
||||
Object* k = dictionary->KeyAt(i);
|
||||
if (k == the_hole) continue;
|
||||
if (k == undefined) continue;
|
||||
|
||||
uint32_t index;
|
||||
if (!k->ToArrayIndex(&index) || index < start_from || index >= length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dictionary->DetailsAt(i).type() == ACCESSOR_CONSTANT) {
|
||||
// Restart from beginning in slow path, otherwise we may observably
|
||||
// access getters out of order
|
||||
return false;
|
||||
} else if (!found) {
|
||||
Object* element_k = dictionary->ValueAt(i);
|
||||
if (value->SameValueZero(element_k)) found = true;
|
||||
}
|
||||
}
|
||||
|
||||
*result = Just(found);
|
||||
return true;
|
||||
}
|
||||
|
||||
static Maybe<bool> IncludesValueImpl(Isolate* isolate,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<Object> value,
|
||||
uint32_t start_from, uint32_t length) {
|
||||
DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
|
||||
bool search_for_hole = value->IsUndefined(isolate);
|
||||
|
||||
if (!search_for_hole) {
|
||||
Maybe<bool> result = Nothing<bool>();
|
||||
if (DictionaryElementsAccessor::IncludesValueFastPath(
|
||||
isolate, receiver, value, start_from, length, &result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Handle<SeededNumberDictionary> dictionary(
|
||||
SeededNumberDictionary::cast(receiver->elements()), isolate);
|
||||
// Iterate through entire range, as accessing elements out of order is
|
||||
// observable
|
||||
for (uint32_t k = start_from; k < length; ++k) {
|
||||
int entry = dictionary->FindEntry(k);
|
||||
if (entry == SeededNumberDictionary::kNotFound) {
|
||||
if (search_for_hole) return Just(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
PropertyDetails details = GetDetailsImpl(receiver->elements(), entry);
|
||||
switch (details.kind()) {
|
||||
case kData: {
|
||||
Object* element_k = dictionary->ValueAt(entry);
|
||||
if (value->SameValueZero(element_k)) return Just(true);
|
||||
break;
|
||||
}
|
||||
case kAccessor: {
|
||||
LookupIterator it(isolate, receiver, k,
|
||||
LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
DCHECK(it.IsFound());
|
||||
DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
|
||||
Handle<Object> element_k;
|
||||
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, element_k, JSObject::GetPropertyWithAccessor(&it),
|
||||
Nothing<bool>());
|
||||
|
||||
if (value->SameValueZero(*element_k)) return Just(true);
|
||||
|
||||
// Some mutation to the prototype elements may have occurred in
|
||||
// accessor.
|
||||
if (!JSObject::PrototypeHasNoElements(isolate, *receiver)) {
|
||||
return IncludesValueSlowPath(isolate, receiver, value, k + 1,
|
||||
length);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Just(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1911,156 +1780,6 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
|
||||
}
|
||||
}
|
||||
|
||||
static Maybe<bool> IncludesValueImpl(Isolate* isolate,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<Object> search_value,
|
||||
uint32_t start_from, uint32_t length) {
|
||||
DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
|
||||
DisallowHeapAllocation no_gc;
|
||||
FixedArrayBase* elements_base = receiver->elements();
|
||||
Object* the_hole = isolate->heap()->the_hole_value();
|
||||
Object* undefined = isolate->heap()->undefined_value();
|
||||
Object* value = *search_value;
|
||||
|
||||
// Elements beyond the capacity of the backing store treated as undefined.
|
||||
if (value == undefined &&
|
||||
static_cast<uint32_t>(elements_base->length()) < length) {
|
||||
return Just(true);
|
||||
}
|
||||
|
||||
if (start_from >= length) return Just(false);
|
||||
|
||||
length = std::min(static_cast<uint32_t>(elements_base->length()), length);
|
||||
|
||||
if (!value->IsNumber()) {
|
||||
if (value == undefined) {
|
||||
// Only FAST_ELEMENTS, FAST_HOLEY_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, and
|
||||
// FAST_HOLEY_DOUBLE_ELEMENTS can have `undefined` as a value.
|
||||
if (!IsFastObjectElementsKind(Subclass::kind()) &&
|
||||
!IsFastHoleyElementsKind(Subclass::kind())) {
|
||||
return Just(false);
|
||||
}
|
||||
|
||||
// Search for `undefined` or The Hole in FAST_ELEMENTS,
|
||||
// FAST_HOLEY_ELEMENTS or FAST_HOLEY_SMI_ELEMENTS
|
||||
if (IsFastSmiOrObjectElementsKind(Subclass::kind())) {
|
||||
auto elements = FixedArray::cast(receiver->elements());
|
||||
|
||||
for (uint32_t k = start_from; k < length; ++k) {
|
||||
Object* element_k = elements->get(k);
|
||||
|
||||
if (IsFastHoleyElementsKind(Subclass::kind()) &&
|
||||
element_k == the_hole) {
|
||||
return Just(true);
|
||||
}
|
||||
if (IsFastObjectElementsKind(Subclass::kind()) &&
|
||||
element_k == undefined) {
|
||||
return Just(true);
|
||||
}
|
||||
}
|
||||
return Just(false);
|
||||
} else {
|
||||
// Seach for The Hole in FAST_HOLEY_DOUBLE_ELEMENTS
|
||||
DCHECK_EQ(Subclass::kind(), FAST_HOLEY_DOUBLE_ELEMENTS);
|
||||
auto elements = FixedDoubleArray::cast(receiver->elements());
|
||||
|
||||
for (uint32_t k = start_from; k < length; ++k) {
|
||||
if (IsFastHoleyElementsKind(Subclass::kind()) &&
|
||||
elements->is_the_hole(k)) {
|
||||
return Just(true);
|
||||
}
|
||||
}
|
||||
return Just(false);
|
||||
}
|
||||
} else if (!IsFastObjectElementsKind(Subclass::kind())) {
|
||||
// Search for non-number, non-Undefined value, with either
|
||||
// FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS or
|
||||
// FAST_HOLEY_DOUBLE_ELEMENTS. Guaranteed to return false, since these
|
||||
// elements kinds can only contain Number values or undefined.
|
||||
return Just(false);
|
||||
} else {
|
||||
// Search for non-number, non-Undefined value with either
|
||||
// FAST_ELEMENTS or FAST_HOLEY_ELEMENTS.
|
||||
DCHECK(IsFastObjectElementsKind(Subclass::kind()));
|
||||
auto elements = FixedArray::cast(receiver->elements());
|
||||
|
||||
for (uint32_t k = start_from; k < length; ++k) {
|
||||
Object* element_k = elements->get(k);
|
||||
if (IsFastHoleyElementsKind(Subclass::kind()) &&
|
||||
element_k == the_hole) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value->SameValueZero(element_k)) return Just(true);
|
||||
}
|
||||
return Just(false);
|
||||
}
|
||||
} else {
|
||||
if (!value->IsNaN()) {
|
||||
double search_value = value->Number();
|
||||
if (IsFastDoubleElementsKind(Subclass::kind())) {
|
||||
// Search for non-NaN Number in FAST_DOUBLE_ELEMENTS or
|
||||
// FAST_HOLEY_DOUBLE_ELEMENTS --- Skip TheHole, and trust UCOMISD or
|
||||
// similar operation for result.
|
||||
auto elements = FixedDoubleArray::cast(receiver->elements());
|
||||
|
||||
for (uint32_t k = start_from; k < length; ++k) {
|
||||
if (IsFastHoleyElementsKind(Subclass::kind()) &&
|
||||
elements->is_the_hole(k)) {
|
||||
continue;
|
||||
}
|
||||
if (elements->get_scalar(k) == search_value) return Just(true);
|
||||
}
|
||||
return Just(false);
|
||||
} else {
|
||||
// Search for non-NaN Number in FAST_ELEMENTS, FAST_HOLEY_ELEMENTS,
|
||||
// FAST_SMI_ELEMENTS or FAST_HOLEY_SMI_ELEMENTS --- Skip non-Numbers,
|
||||
// and trust UCOMISD or similar operation for result
|
||||
auto elements = FixedArray::cast(receiver->elements());
|
||||
|
||||
for (uint32_t k = start_from; k < length; ++k) {
|
||||
Object* element_k = elements->get(k);
|
||||
if (element_k->IsNumber() && element_k->Number() == search_value) {
|
||||
return Just(true);
|
||||
}
|
||||
}
|
||||
return Just(false);
|
||||
}
|
||||
} else {
|
||||
// Search for NaN --- NaN cannot be represented with Smi elements, so
|
||||
// abort if ElementsKind is FAST_SMI_ELEMENTS or FAST_HOLEY_SMI_ELEMENTS
|
||||
if (IsFastSmiElementsKind(Subclass::kind())) return Just(false);
|
||||
|
||||
if (IsFastDoubleElementsKind(Subclass::kind())) {
|
||||
// Search for NaN in FAST_DOUBLE_ELEMENTS or
|
||||
// FAST_HOLEY_DOUBLE_ELEMENTS --- Skip The Hole and trust
|
||||
// std::isnan(elementK) for result
|
||||
auto elements = FixedDoubleArray::cast(receiver->elements());
|
||||
|
||||
for (uint32_t k = start_from; k < length; ++k) {
|
||||
if (IsFastHoleyElementsKind(Subclass::kind()) &&
|
||||
elements->is_the_hole(k)) {
|
||||
continue;
|
||||
}
|
||||
if (std::isnan(elements->get_scalar(k))) return Just(true);
|
||||
}
|
||||
return Just(false);
|
||||
} else {
|
||||
// Search for NaN in FAST_ELEMENTS, FAST_HOLEY_ELEMENTS,
|
||||
// FAST_SMI_ELEMENTS or FAST_HOLEY_SMI_ELEMENTS. Return true if
|
||||
// elementK->IsHeapNumber() && std::isnan(elementK->Number())
|
||||
DCHECK(IsFastSmiOrObjectElementsKind(Subclass::kind()));
|
||||
auto elements = FixedArray::cast(receiver->elements());
|
||||
|
||||
for (uint32_t k = start_from; k < length; ++k) {
|
||||
if (elements->get(k)->IsNaN()) return Just(true);
|
||||
}
|
||||
return Just(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// SpliceShrinkStep might modify the backing_store.
|
||||
static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver,
|
||||
@ -2406,9 +2125,9 @@ class FastHoleyDoubleElementsAccessor
|
||||
|
||||
|
||||
// Super class for all external element arrays.
|
||||
template <ElementsKind Kind, typename ctype>
|
||||
template<ElementsKind Kind>
|
||||
class TypedElementsAccessor
|
||||
: public ElementsAccessorBase<TypedElementsAccessor<Kind, ctype>,
|
||||
: public ElementsAccessorBase<TypedElementsAccessor<Kind>,
|
||||
ElementsKindTraits<Kind> > {
|
||||
public:
|
||||
explicit TypedElementsAccessor(const char* name)
|
||||
@ -2416,7 +2135,7 @@ class TypedElementsAccessor
|
||||
ElementsKindTraits<Kind> >(name) {}
|
||||
|
||||
typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
|
||||
typedef TypedElementsAccessor<Kind, ctype> AccessorClass;
|
||||
typedef TypedElementsAccessor<Kind> AccessorClass;
|
||||
|
||||
static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
|
||||
Object* value) {
|
||||
@ -2522,53 +2241,12 @@ class TypedElementsAccessor
|
||||
*nof_items = count;
|
||||
return Just(true);
|
||||
}
|
||||
|
||||
static Maybe<bool> IncludesValueImpl(Isolate* isolate,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<Object> value,
|
||||
uint32_t start_from, uint32_t length) {
|
||||
DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
|
||||
DisallowHeapAllocation no_gc;
|
||||
|
||||
BackingStore* elements = BackingStore::cast(receiver->elements());
|
||||
if (value->IsUndefined(isolate) &&
|
||||
length > static_cast<uint32_t>(elements->length())) {
|
||||
return Just(true);
|
||||
}
|
||||
if (!value->IsNumber()) return Just(false);
|
||||
|
||||
double search_value = value->Number();
|
||||
|
||||
if (!std::isfinite(search_value)) {
|
||||
// Integral types cannot represent +Inf or NaN
|
||||
if (AccessorClass::kind() < FLOAT32_ELEMENTS ||
|
||||
AccessorClass::kind() > FLOAT64_ELEMENTS) {
|
||||
return Just(false);
|
||||
}
|
||||
} else if (search_value < std::numeric_limits<ctype>::lowest() ||
|
||||
search_value > std::numeric_limits<ctype>::max()) {
|
||||
// Return false if value can't be represented in this space
|
||||
return Just(false);
|
||||
}
|
||||
|
||||
if (!std::isnan(search_value)) {
|
||||
for (uint32_t k = start_from; k < length; ++k) {
|
||||
double element_k = elements->get_scalar(k);
|
||||
if (element_k == search_value) return Just(true);
|
||||
}
|
||||
return Just(false);
|
||||
} else {
|
||||
for (uint32_t k = start_from; k < length; ++k) {
|
||||
double element_k = elements->get_scalar(k);
|
||||
if (std::isnan(element_k)) return Just(true);
|
||||
}
|
||||
return Just(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
|
||||
typedef TypedElementsAccessor<TYPE##_ELEMENTS, ctype> \
|
||||
typedef TypedElementsAccessor<TYPE##_ELEMENTS > \
|
||||
Fixed##Type##ElementsAccessor;
|
||||
|
||||
TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
|
||||
@ -2803,46 +2481,6 @@ class SloppyArgumentsElementsAccessor
|
||||
isolate, object, store, convert, filter, list, nof_indices,
|
||||
insertion_index);
|
||||
}
|
||||
|
||||
static Maybe<bool> IncludesValueImpl(Isolate* isolate,
|
||||
Handle<JSObject> object,
|
||||
Handle<Object> value,
|
||||
uint32_t start_from, uint32_t length) {
|
||||
DCHECK(JSObject::PrototypeHasNoElements(isolate, *object));
|
||||
Handle<Map> original_map = handle(object->map(), isolate);
|
||||
FixedArray* parameter_map = FixedArray::cast(object->elements());
|
||||
bool search_for_hole = value->IsUndefined(isolate);
|
||||
|
||||
for (uint32_t k = start_from; k < length; ++k) {
|
||||
uint32_t entry =
|
||||
GetEntryForIndexImpl(*object, parameter_map, k, ALL_PROPERTIES);
|
||||
if (entry == kMaxUInt32) {
|
||||
if (search_for_hole) return Just(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
Handle<Object> element_k = GetImpl(parameter_map, entry);
|
||||
|
||||
if (element_k->IsAccessorPair()) {
|
||||
LookupIterator it(isolate, object, k, LookupIterator::OWN);
|
||||
DCHECK(it.IsFound());
|
||||
DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
|
||||
Object::GetPropertyWithAccessor(&it),
|
||||
Nothing<bool>());
|
||||
|
||||
if (value->SameValueZero(*element_k)) return Just(true);
|
||||
|
||||
if (object->map() != *original_map) {
|
||||
// Some mutation occurred in accessor. Abort "fast" path
|
||||
return IncludesValueSlowPath(isolate, object, value, k + 1, length);
|
||||
}
|
||||
} else if (value->SameValueZero(*element_k)) {
|
||||
return Just(true);
|
||||
}
|
||||
}
|
||||
return Just(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -154,12 +154,6 @@ class ElementsAccessor {
|
||||
virtual uint32_t GetCapacity(JSObject* holder,
|
||||
FixedArrayBase* backing_store) = 0;
|
||||
|
||||
// Check an Object's own elements for an element (using SameValueZero
|
||||
// semantics)
|
||||
virtual Maybe<bool> IncludesValue(Isolate* isolate, Handle<JSObject> receiver,
|
||||
Handle<Object> value, uint32_t start,
|
||||
uint32_t length) = 0;
|
||||
|
||||
protected:
|
||||
friend class LookupIterator;
|
||||
|
||||
|
@ -380,16 +380,6 @@ class Factory final {
|
||||
}
|
||||
return NewNumber(static_cast<double>(value), pretenure);
|
||||
}
|
||||
Handle<Object> NewNumberFromInt64(int64_t value,
|
||||
PretenureFlag pretenure = NOT_TENURED) {
|
||||
if (value <= std::numeric_limits<int32_t>::max() &&
|
||||
value >= std::numeric_limits<int32_t>::min() &&
|
||||
Smi::IsValid(static_cast<int32_t>(value))) {
|
||||
return Handle<Object>(Smi::FromInt(static_cast<int32_t>(value)),
|
||||
isolate());
|
||||
}
|
||||
return NewNumber(static_cast<double>(value), pretenure);
|
||||
}
|
||||
Handle<HeapNumber> NewHeapNumber(double value,
|
||||
MutableMode mode = IMMUTABLE,
|
||||
PretenureFlag pretenure = NOT_TENURED);
|
||||
|
@ -1492,6 +1492,47 @@ function ArrayFill(value, start, end) {
|
||||
}
|
||||
|
||||
|
||||
function InnerArrayIncludes(searchElement, fromIndex, array, length) {
|
||||
if (length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var n = TO_INTEGER(fromIndex);
|
||||
|
||||
var k;
|
||||
if (n >= 0) {
|
||||
k = n;
|
||||
} else {
|
||||
k = length + n;
|
||||
if (k < 0) {
|
||||
k = 0;
|
||||
}
|
||||
}
|
||||
|
||||
while (k < length) {
|
||||
var elementK = array[k];
|
||||
if (%SameValueZero(searchElement, elementK)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
++k;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// ES2016 draft, section 22.1.3.11
|
||||
function ArrayIncludes(searchElement, fromIndex) {
|
||||
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.includes");
|
||||
|
||||
var array = TO_OBJECT(this);
|
||||
var length = TO_LENGTH(array.length);
|
||||
|
||||
return InnerArrayIncludes(searchElement, fromIndex, array, length);
|
||||
}
|
||||
|
||||
|
||||
// ES6, draft 10-14-14, section 22.1.2.1
|
||||
function ArrayFrom(arrayLike, mapfn, receiver) {
|
||||
var items = TO_OBJECT(arrayLike);
|
||||
@ -1636,7 +1677,7 @@ utils.InstallFunctions(GlobalArray.prototype, DONT_ENUM, [
|
||||
"find", getFunction("find", ArrayFind, 1),
|
||||
"findIndex", getFunction("findIndex", ArrayFindIndex, 1),
|
||||
"fill", getFunction("fill", ArrayFill, 1),
|
||||
"includes", getFunction("includes", null, 1)
|
||||
"includes", getFunction("includes", ArrayIncludes, 1),
|
||||
]);
|
||||
|
||||
utils.InstallGetter(GlobalArray, speciesSymbol, ArraySpecies);
|
||||
@ -1690,6 +1731,7 @@ utils.Export(function(to) {
|
||||
to.InnerArrayFind = InnerArrayFind;
|
||||
to.InnerArrayFindIndex = InnerArrayFindIndex;
|
||||
to.InnerArrayForEach = InnerArrayForEach;
|
||||
to.InnerArrayIncludes = InnerArrayIncludes;
|
||||
to.InnerArrayIndexOf = InnerArrayIndexOf;
|
||||
to.InnerArrayJoin = InnerArrayJoin;
|
||||
to.InnerArrayLastIndexOf = InnerArrayLastIndexOf;
|
||||
|
@ -28,6 +28,7 @@ var InnerArrayFilter;
|
||||
var InnerArrayFind;
|
||||
var InnerArrayFindIndex;
|
||||
var InnerArrayForEach;
|
||||
var InnerArrayIncludes;
|
||||
var InnerArrayIndexOf;
|
||||
var InnerArrayJoin;
|
||||
var InnerArrayLastIndexOf;
|
||||
@ -81,6 +82,7 @@ utils.Import(function(from) {
|
||||
InnerArrayFind = from.InnerArrayFind;
|
||||
InnerArrayFindIndex = from.InnerArrayFindIndex;
|
||||
InnerArrayForEach = from.InnerArrayForEach;
|
||||
InnerArrayIncludes = from.InnerArrayIncludes;
|
||||
InnerArrayIndexOf = from.InnerArrayIndexOf;
|
||||
InnerArrayJoin = from.InnerArrayJoin;
|
||||
InnerArrayLastIndexOf = from.InnerArrayLastIndexOf;
|
||||
@ -711,29 +713,7 @@ function TypedArrayIncludes(searchElement, fromIndex) {
|
||||
|
||||
var length = %_TypedArrayGetLength(this);
|
||||
|
||||
if (length === 0) return false;
|
||||
var n = TO_INTEGER(fromIndex);
|
||||
|
||||
var k;
|
||||
if (n >= 0) {
|
||||
k = n;
|
||||
} else {
|
||||
k = length + n;
|
||||
if (k < 0) {
|
||||
k = 0;
|
||||
}
|
||||
}
|
||||
|
||||
while (k < length) {
|
||||
var elementK = this[k];
|
||||
if (%SameValueZero(searchElement, elementK)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
++k;
|
||||
}
|
||||
|
||||
return false;
|
||||
return InnerArrayIncludes(searchElement, fromIndex, this, length);
|
||||
}
|
||||
%FunctionSetLength(TypedArrayIncludes, 1);
|
||||
|
||||
|
@ -1144,20 +1144,6 @@ MUST_USE_RESULT MaybeHandle<FixedArray> JSReceiver::OwnPropertyKeys(
|
||||
GetKeysConversion::kConvertToString);
|
||||
}
|
||||
|
||||
bool JSObject::PrototypeHasNoElements(Isolate* isolate, JSObject* object) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
HeapObject* prototype = HeapObject::cast(object->map()->prototype());
|
||||
HeapObject* null = isolate->heap()->null_value();
|
||||
HeapObject* empty = isolate->heap()->empty_fixed_array();
|
||||
while (prototype != null) {
|
||||
Map* map = prototype->map();
|
||||
if (map->instance_type() <= LAST_CUSTOM_ELEMENTS_RECEIVER) return false;
|
||||
if (JSObject::cast(prototype)->elements() != empty) return false;
|
||||
prototype = HeapObject::cast(map->prototype());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define FIELD_ADDR(p, offset) \
|
||||
(reinterpret_cast<byte*>(p) + offset - kHeapObjectTag)
|
||||
|
||||
|
@ -2210,9 +2210,6 @@ class JSObject: public JSReceiver {
|
||||
static bool UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate);
|
||||
static void InvalidatePrototypeChains(Map* map);
|
||||
|
||||
// Utility used by many Array builtins and runtime functions
|
||||
static inline bool PrototypeHasNoElements(Isolate* isolate, JSObject* object);
|
||||
|
||||
// Alternative implementation of WeakFixedArray::NullCallback.
|
||||
class PrototypeRegistryCompactionCallback {
|
||||
public:
|
||||
|
@ -32,24 +32,18 @@ RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) {
|
||||
}
|
||||
|
||||
static void InstallCode(Isolate* isolate, Handle<JSObject> holder,
|
||||
const char* name, Handle<Code> code, int argc = -1) {
|
||||
const char* name, Handle<Code> code) {
|
||||
Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
|
||||
Handle<JSFunction> optimized =
|
||||
isolate->factory()->NewFunctionWithoutPrototype(key, code);
|
||||
if (argc < 0) {
|
||||
optimized->shared()->DontAdaptArguments();
|
||||
} else {
|
||||
optimized->shared()->set_internal_formal_parameter_count(argc);
|
||||
}
|
||||
JSObject::AddProperty(holder, key, optimized, NONE);
|
||||
}
|
||||
|
||||
static void InstallBuiltin(Isolate* isolate, Handle<JSObject> holder,
|
||||
const char* name, Builtins::Name builtin_name,
|
||||
int argc = -1) {
|
||||
const char* name, Builtins::Name builtin_name) {
|
||||
InstallCode(isolate, holder, name,
|
||||
handle(isolate->builtins()->builtin(builtin_name), isolate),
|
||||
argc);
|
||||
handle(isolate->builtins()->builtin(builtin_name), isolate));
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
|
||||
@ -69,7 +63,6 @@ RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
|
||||
InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
|
||||
InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
|
||||
InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
|
||||
InstallBuiltin(isolate, holder, "includes", Builtins::kArrayIncludes, 2);
|
||||
|
||||
return *holder;
|
||||
}
|
||||
@ -450,98 +443,5 @@ RUNTIME_FUNCTION(Runtime_ArraySpeciesConstructor) {
|
||||
isolate, Object::ArraySpeciesConstructor(isolate, original_array));
|
||||
}
|
||||
|
||||
// ES7 22.1.3.11 Array.prototype.includes
|
||||
RUNTIME_FUNCTION(Runtime_ArrayIncludes_Slow) {
|
||||
HandleScope shs(isolate);
|
||||
DCHECK(args.length() == 3);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, search_element, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, from_index, 2);
|
||||
|
||||
// Let O be ? ToObject(this value).
|
||||
Handle<JSReceiver> object;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, object, Object::ToObject(isolate, handle(args[0], isolate)));
|
||||
|
||||
// Let len be ? ToLength(? Get(O, "length")).
|
||||
int64_t len;
|
||||
{
|
||||
if (object->map()->instance_type() == JS_ARRAY_TYPE) {
|
||||
uint32_t len32;
|
||||
bool success = JSArray::cast(*object)->length()->ToArrayLength(&len32);
|
||||
DCHECK(success);
|
||||
USE(success);
|
||||
len = len32;
|
||||
} else {
|
||||
Handle<Object> len_;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, len_,
|
||||
Object::GetProperty(object, isolate->factory()->length_string()));
|
||||
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len_,
|
||||
Object::ToLength(isolate, len_));
|
||||
len = static_cast<int64_t>(len_->Number());
|
||||
DCHECK_EQ(len, len_->Number());
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 0) return isolate->heap()->false_value();
|
||||
|
||||
// Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step
|
||||
// produces the value 0.)
|
||||
int64_t start_from;
|
||||
{
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, from_index,
|
||||
Object::ToInteger(isolate, from_index));
|
||||
double fp = from_index->Number();
|
||||
if (fp > len) return isolate->heap()->false_value();
|
||||
start_from = static_cast<int64_t>(fp);
|
||||
}
|
||||
|
||||
int64_t index;
|
||||
if (start_from >= 0) {
|
||||
index = start_from;
|
||||
} else {
|
||||
index = len + start_from;
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If the receiver is not a special receiver type, and the length is a valid
|
||||
// element index, perform fast operation tailored to specific ElementsKinds.
|
||||
if (object->map()->instance_type() > LAST_SPECIAL_RECEIVER_TYPE &&
|
||||
len < kMaxUInt32 &&
|
||||
JSObject::PrototypeHasNoElements(isolate, JSObject::cast(*object))) {
|
||||
Handle<JSObject> obj = Handle<JSObject>::cast(object);
|
||||
ElementsAccessor* elements = obj->GetElementsAccessor();
|
||||
Maybe<bool> result = elements->IncludesValue(isolate, obj, search_element,
|
||||
static_cast<uint32_t>(index),
|
||||
static_cast<uint32_t>(len));
|
||||
MAYBE_RETURN(result, isolate->heap()->exception());
|
||||
return *isolate->factory()->ToBoolean(result.FromJust());
|
||||
}
|
||||
|
||||
// Otherwise, perform slow lookups for special receiver types
|
||||
for (; index < len; ++index) {
|
||||
// Let elementK be the result of ? Get(O, ! ToString(k)).
|
||||
Handle<Object> element_k;
|
||||
{
|
||||
Handle<Object> index_obj = isolate->factory()->NewNumberFromInt64(index);
|
||||
bool success;
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(
|
||||
isolate, object, index_obj, &success);
|
||||
DCHECK(success);
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_k,
|
||||
Object::GetProperty(&it));
|
||||
}
|
||||
|
||||
// If SameValueZero(searchElement, elementK) is true, return true.
|
||||
if (search_element->SameValueZero(*element_k)) {
|
||||
return isolate->heap()->true_value();
|
||||
}
|
||||
}
|
||||
return isolate->heap()->false_value();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -55,8 +55,7 @@ namespace internal {
|
||||
F(GetCachedArrayIndex, 1, 1) \
|
||||
F(FixedArrayGet, 2, 1) \
|
||||
F(FixedArraySet, 3, 1) \
|
||||
F(ArraySpeciesConstructor, 1, 1) \
|
||||
F(ArrayIncludes_Slow, 3, 1)
|
||||
F(ArraySpeciesConstructor, 1, 1)
|
||||
|
||||
#define FOR_EACH_INTRINSIC_ATOMICS(F) \
|
||||
F(ThrowNotIntegerSharedTypedArrayError, 1, 1) \
|
||||
|
@ -1,634 +0,0 @@
|
||||
// Copyright 2016 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
|
||||
|
||||
// Ensure `Array.prototype.includes` functions correctly for numerous elements
|
||||
// kinds, and various exotic receiver types,
|
||||
|
||||
// TODO(caitp): update kIterCount to a high enough number to trigger inlining,
|
||||
// once inlining this builtin is supported
|
||||
var kIterCount = 1;
|
||||
var kTests = {
|
||||
Array: {
|
||||
FAST_ELEMENTS() {
|
||||
var r = /foo/;
|
||||
var s = new String("bar");
|
||||
var p = new Proxy({}, {});
|
||||
var o = {};
|
||||
|
||||
var array = [r, s, p];
|
||||
assertTrue(%HasFastObjectElements(array));
|
||||
assertFalse(%HasFastHoleyElements(array));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(array.includes(p));
|
||||
assertFalse(array.includes(o));
|
||||
}
|
||||
},
|
||||
|
||||
FAST_HOLEY_ELEMENTS() {
|
||||
var r = /foo/;
|
||||
var p = new Proxy({}, {});
|
||||
var o = {};
|
||||
|
||||
var array = [r, , p];
|
||||
assertTrue(%HasFastObjectElements(array));
|
||||
assertTrue(%HasFastHoleyElements(array));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(array.includes(p));
|
||||
assertFalse(array.includes(o));
|
||||
}
|
||||
},
|
||||
|
||||
FAST_SMI_ELEMENTS() {
|
||||
var array = [0, 88, 9999, 1, -5, 7];
|
||||
assertTrue(%HasFastSmiElements(array));
|
||||
assertFalse(%HasFastHoleyElements(array));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(array.includes(9999));
|
||||
assertTrue(array.includes(-5));
|
||||
assertFalse(array.includes(-5.00001));
|
||||
assertFalse(array.includes(undefined));
|
||||
assertFalse(array.includes(NaN));
|
||||
}
|
||||
},
|
||||
|
||||
FAST_HOLEY_SMI_ELEMENTS() {
|
||||
var array = [49, , , 72, , , 67, -48];
|
||||
assertTrue(%HasFastSmiElements(array));
|
||||
assertTrue(%HasFastHoleyElements(array));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(array.includes(72));
|
||||
assertTrue(array.includes(-48));
|
||||
assertFalse(array.includes(72, 4));
|
||||
assertTrue(array.includes(undefined));
|
||||
assertFalse(array.includes(undefined, -2));
|
||||
assertFalse(array.includes(NaN));
|
||||
}
|
||||
},
|
||||
|
||||
FAST_DOUBLE_ELEMENTS() {
|
||||
var array = [7.00000001, -13000.89412, 73451.4124,
|
||||
5824.48, 6.0000495, 48.3488, 44.0, 76.35, NaN, 78.4];
|
||||
assertTrue(%HasFastDoubleElements(array));
|
||||
assertFalse(%HasFastHoleyElements(array));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(array.includes(7.00000001));
|
||||
assertFalse(array.includes(7.00000001, 2));
|
||||
assertTrue(array.includes(NaN));
|
||||
assertFalse(array.includes(NaN, -1));
|
||||
assertTrue(array.includes(-13000.89412));
|
||||
assertFalse(array.includes(-13000.89412, -2));
|
||||
assertFalse(array.includes(undefined));
|
||||
}
|
||||
},
|
||||
|
||||
FAST_HOLEY_DOUBLE_ELEMENTS() {
|
||||
var array = [7.00000001, -13000.89412, ,
|
||||
5824.48, , 48.3488, , NaN, , 78.4];
|
||||
assertTrue(%HasFastDoubleElements(array));
|
||||
assertTrue(%HasFastHoleyElements(array));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(array.includes(7.00000001));
|
||||
assertFalse(array.includes(7.00000001, 2));
|
||||
assertTrue(array.includes(NaN));
|
||||
assertFalse(array.includes(NaN, -2));
|
||||
assertTrue(array.includes(-13000.89412));
|
||||
assertFalse(array.includes(-13000.89412, -2));
|
||||
assertTrue(array.includes(undefined, -2));
|
||||
assertFalse(array.includes(undefined, -1));
|
||||
}
|
||||
},
|
||||
|
||||
DICTIONARY_ELEMENTS() {
|
||||
var array = [];
|
||||
Object.defineProperty(array, 4, { get() { return NaN; } });
|
||||
Object.defineProperty(array, 7, { value: Function });
|
||||
|
||||
assertTrue(%HasDictionaryElements(array));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(array.includes(NaN));
|
||||
assertFalse(array.includes(NaN, -3));
|
||||
assertTrue(array.includes(Function));
|
||||
assertTrue(array.includes(undefined));
|
||||
assertFalse(array.includes(undefined, 7));
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
Object: {
|
||||
FAST_ELEMENTS() {
|
||||
var r = /foo/;
|
||||
var s = new String("bar");
|
||||
var p = new Proxy({}, {});
|
||||
var o = {};
|
||||
|
||||
var object = { 0: r, 1: s, 2: p, length: 3 };
|
||||
assertTrue(%HasFastObjectElements(object));
|
||||
// TODO(caitp): JSObjects always seem to start with FAST_HOLEY_ELEMENTS
|
||||
// assertFalse(%HasFastHoleyElements(object));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(Array.prototype.includes.call(object, p));
|
||||
assertFalse(Array.prototype.includes.call(object, o));
|
||||
}
|
||||
},
|
||||
|
||||
FAST_HOLEY_ELEMENTS() {
|
||||
var r = /foo/;
|
||||
var p = new Proxy({}, {});
|
||||
var o = {};
|
||||
|
||||
var object = { 0: r, 2: p, length: 3 };
|
||||
assertTrue(%HasFastObjectElements(object));
|
||||
assertTrue(%HasFastHoleyElements(object));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(Array.prototype.includes.call(object, p));
|
||||
assertFalse(Array.prototype.includes.call(object, o));
|
||||
}
|
||||
},
|
||||
|
||||
FAST_SMI_ELEMENTS() {
|
||||
var object = { 0: 0, 1: 88, 2: 9999, 3: 1, 4: -5, 5: 7, length: 6 };
|
||||
// TODO(caitp): JSObjects always seem to start with FAST_HOLEY_ELEMENTS
|
||||
// assertTrue(%HasFastSmiElements(object));
|
||||
// assertFalse(%HasFastHoleyElements(object));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(Array.prototype.includes.call(object, 9999));
|
||||
assertTrue(Array.prototype.includes.call(object, -5));
|
||||
assertFalse(Array.prototype.includes.call(object, -5.00001));
|
||||
assertFalse(Array.prototype.includes.call(object, undefined));
|
||||
assertFalse(Array.prototype.includes.call(object, NaN));
|
||||
}
|
||||
},
|
||||
|
||||
FAST_HOLEY_SMI_ELEMENTS() {
|
||||
var object = { 0: 49, 3: 72, 6: 67, 7: -48, length: 8 };
|
||||
// TODO(caitp): JSObjects always seem to start with FAST_HOLEY_ELEMENTS
|
||||
// assertTrue(%HasFastSmiElements(object));
|
||||
// assertTrue(%HasFastHoleyElements(object));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(Array.prototype.includes.call(object, 72));
|
||||
assertTrue(Array.prototype.includes.call(object, -48));
|
||||
assertFalse(Array.prototype.includes.call(object, 72, 4));
|
||||
assertTrue(Array.prototype.includes.call(object, undefined));
|
||||
assertFalse(Array.prototype.includes.call(object, undefined, -2));
|
||||
assertFalse(Array.prototype.includes.call(object, NaN));
|
||||
}
|
||||
},
|
||||
|
||||
FAST_DOUBLE_ELEMENTS() {
|
||||
var object = { 0: 7.00000001, 1: -13000.89412, 2: 73451.4124,
|
||||
3: 5824.48, 4: 6.0000495, 5: 48.3488, 6: 44.0, 7: 76.35,
|
||||
8: NaN, 9: 78.4, length: 10 };
|
||||
// TODO(caitp): JSObjects always seem to start with FAST_HOLEY_ELEMENTS
|
||||
// assertTrue(%HasFastDoubleElements(object));
|
||||
// assertFalse(%HasFastHoleyElements(object));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(Array.prototype.includes.call(object, 7.00000001));
|
||||
assertFalse(Array.prototype.includes.call(object, 7.00000001, 2));
|
||||
assertTrue(Array.prototype.includes.call(object, NaN));
|
||||
assertFalse(Array.prototype.includes.call(object, NaN, -1));
|
||||
assertTrue(Array.prototype.includes.call(object, -13000.89412));
|
||||
assertFalse(Array.prototype.includes.call(object, -13000.89412, -2));
|
||||
assertFalse(Array.prototype.includes.call(object, undefined));
|
||||
}
|
||||
},
|
||||
|
||||
FAST_HOLEY_DOUBLE_ELEMENTS() {
|
||||
var object = { 0: 7.00000001, 1: -13000.89412, 3: 5824.48, 5: 48.3488,
|
||||
7: NaN, 9: 78.4, length: 10 };
|
||||
// TODO(caitp): JSObjects always seem to start with FAST_HOLEY_ELEMENTS
|
||||
// assertTrue(%HasFastDoubleElements(object));
|
||||
// assertTrue(%HasFastHoleyElements(object));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(Array.prototype.includes.call(object, 7.00000001));
|
||||
assertFalse(Array.prototype.includes.call(object, 7.00000001, 2));
|
||||
assertTrue(Array.prototype.includes.call(object, NaN));
|
||||
assertFalse(Array.prototype.includes.call(object, NaN, -2));
|
||||
assertTrue(Array.prototype.includes.call(object, -13000.89412));
|
||||
assertFalse(Array.prototype.includes.call(object, -13000.89412, -2));
|
||||
assertTrue(Array.prototype.includes.call(object, undefined, -2));
|
||||
assertFalse(Array.prototype.includes.call(object, undefined, -1));
|
||||
}
|
||||
},
|
||||
|
||||
DICTIONARY_ELEMENTS() {
|
||||
var object = { length: 8 };
|
||||
Object.defineProperty(object, 4, { get() { return NaN; } });
|
||||
Object.defineProperty(object, 7, { value: Function });
|
||||
|
||||
assertTrue(%HasDictionaryElements(object));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(Array.prototype.includes.call(object, NaN));
|
||||
assertFalse(Array.prototype.includes.call(object, NaN, -3));
|
||||
assertTrue(Array.prototype.includes.call(object, Function));
|
||||
assertTrue(Array.prototype.includes.call(object, undefined));
|
||||
assertFalse(Array.prototype.includes.call(object, undefined, 7));
|
||||
}
|
||||
|
||||
(function prototypeModifiedDuringAccessor() {
|
||||
function O() {
|
||||
return {
|
||||
__proto__: {},
|
||||
get 0() {
|
||||
this.__proto__.__proto__ = {
|
||||
get 1() {
|
||||
this[2] = "c";
|
||||
return "b";
|
||||
}
|
||||
};
|
||||
return "a";
|
||||
},
|
||||
length: 3
|
||||
};
|
||||
}
|
||||
|
||||
// Switch to slow path when first accessor modifies the prototype
|
||||
assertTrue(Array.prototype.includes.call(O(), "a"));
|
||||
assertTrue(Array.prototype.includes.call(O(), "b"));
|
||||
assertTrue(Array.prototype.includes.call(O(), "c"));
|
||||
|
||||
// Avoid switching to slow path due to avoiding the accessor
|
||||
assertFalse(Array.prototype.includes.call(O(), "c", 2));
|
||||
assertFalse(Array.prototype.includes.call(O(), "b", 1));
|
||||
assertTrue(Array.prototype.includes.call(O(), undefined, 1));
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
String: {
|
||||
FAST_STRING_ELEMENTS() {
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(Array.prototype.includes.call("froyo", "y"));
|
||||
assertFalse(Array.prototype.includes.call("froyo", "y", -1));
|
||||
assertTrue(Array.prototype.includes.call("froyo", "y", -2));
|
||||
assertFalse(Array.prototype.includes.call("froyo", NaN));
|
||||
assertFalse(Array.prototype.includes.call("froyo", undefined));
|
||||
}
|
||||
},
|
||||
|
||||
SLOW_STRING_ELEMENTS() {
|
||||
var string = new String("froyo");
|
||||
|
||||
// Never accessible from A.p.includes as 'length' is not configurable
|
||||
Object.defineProperty(string, 34, { value: NaN });
|
||||
Object.defineProperty(string, 12, { get() { return "nope" } });
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertTrue(Array.prototype.includes.call("froyo", "y"));
|
||||
assertFalse(Array.prototype.includes.call("froyo", "y", -1));
|
||||
assertTrue(Array.prototype.includes.call("froyo", "y", -2));
|
||||
assertFalse(Array.prototype.includes.call(string, NaN));
|
||||
assertFalse(Array.prototype.includes.call(string, undefined));
|
||||
assertFalse(Array.prototype.includes.call(string, "nope"));
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
Arguments: {
|
||||
FAST_SLOPPY_ARGUMENTS_ELEMENTS() {
|
||||
var args = (function(a, b) { return arguments; })("foo", NaN, "bar");
|
||||
assertTrue(%HasSloppyArgumentsElements(args));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertFalse(Array.prototype.includes.call(args, undefined));
|
||||
assertTrue(Array.prototype.includes.call(args, NaN));
|
||||
assertFalse(Array.prototype.includes.call(args, NaN, -1));
|
||||
assertTrue(Array.prototype.includes.call(args, "bar", -1));
|
||||
}
|
||||
},
|
||||
|
||||
SLOW_SLOPPY_ARGUMENTS_ELEMENTS() {
|
||||
var args = (function(a, a) { return arguments; })("foo", NaN, "bar");
|
||||
Object.defineProperty(args, 3, { get() { return "silver"; } });
|
||||
Object.defineProperty(args, "length", { value: 4 });
|
||||
assertTrue(%HasSloppyArgumentsElements(args));
|
||||
|
||||
for (var i = 0; i < kIterCount; ++i) {
|
||||
assertFalse(Array.prototype.includes.call(args, undefined));
|
||||
assertTrue(Array.prototype.includes.call(args, NaN));
|
||||
assertFalse(Array.prototype.includes.call(args, NaN, -2));
|
||||
assertTrue(Array.prototype.includes.call(args, "bar", -2));
|
||||
assertTrue(Array.prototype.includes.call(args, "silver", -1));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
TypedArray: {
|
||||
Int8Array() {
|
||||
var array = new Int8Array([-129, 128,
|
||||
NaN /* 0 */, +0 /* 0 */, -0 /* 0 */,
|
||||
+Infinity /* 0 */, -Infinity /* 0 */,
|
||||
255 /* -1 */, 127 /* 127 */, -255 /* 1 */]);
|
||||
assertFalse(Array.prototype.includes.call(array, -129));
|
||||
assertFalse(Array.prototype.includes.call(array, 128));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 2));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 3));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 4));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 5));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 6));
|
||||
assertFalse(Array.prototype.includes.call(array, 0, 7));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, -1, 7));
|
||||
assertFalse(Array.prototype.includes.call(array, -1, 8));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 127, 8));
|
||||
assertFalse(Array.prototype.includes.call(array, 127, 9));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 1, 9));
|
||||
},
|
||||
|
||||
Detached_Int8Array() {
|
||||
var array = new Int8Array(10);
|
||||
%ArrayBufferNeuter(array.buffer);
|
||||
assertFalse(Array.prototype.includes.call(array, 0));
|
||||
assertFalse(Array.prototype.includes.call(array, 0, 10));
|
||||
},
|
||||
|
||||
Uint8Array() {
|
||||
var array = new Uint8Array([-1, 256,
|
||||
NaN /* 0 */, +0 /* 0 */, -0 /* 0 */,
|
||||
+Infinity /* 0 */, -Infinity /* 0 */,
|
||||
255 /* 255 */, 257 /* 1 */, -128 /* 128 */,
|
||||
-2 /* 254 */]);
|
||||
assertFalse(Array.prototype.includes.call(array, -1));
|
||||
assertFalse(Array.prototype.includes.call(array, 256));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 2));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 3));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 4));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 5));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 6));
|
||||
assertFalse(Array.prototype.includes.call(array, 0, 7));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 255, 7));
|
||||
assertFalse(Array.prototype.includes.call(array, 255, 8));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 1, 8));
|
||||
assertFalse(Array.prototype.includes.call(array, 1, 9));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 128, 9));
|
||||
assertFalse(Array.prototype.includes.call(array, 128, 10));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 254, 10));
|
||||
},
|
||||
|
||||
Detached_Uint8Array() {
|
||||
var array = new Uint8Array(10);
|
||||
%ArrayBufferNeuter(array.buffer);
|
||||
assertFalse(Array.prototype.includes.call(array, 0));
|
||||
assertFalse(Array.prototype.includes.call(array, 0, 10));
|
||||
},
|
||||
|
||||
Uint8ClampedArray() {
|
||||
var array = new Uint8ClampedArray([-1 /* 0 */, NaN /* 0 */, 256 /* 255 */,
|
||||
127.6 /* 128 */, 127.4 /* 127 */,
|
||||
121.5 /* 122 */, 124.5 /* 124 */]);
|
||||
assertFalse(Array.prototype.includes.call(array, -1));
|
||||
assertFalse(Array.prototype.includes.call(array, 256));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 0));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 1));
|
||||
assertTrue(Array.prototype.includes.call(array, 255, 2));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 128, 3));
|
||||
assertFalse(Array.prototype.includes.call(array, 128, 4));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 127, 4));
|
||||
assertFalse(Array.prototype.includes.call(array, 127, 5));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 122, 5));
|
||||
assertFalse(Array.prototype.includes.call(array, 122, 6));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 124, 6));
|
||||
},
|
||||
|
||||
Detached_Uint8ClampedArray() {
|
||||
var array = new Uint8ClampedArray(10);
|
||||
%ArrayBufferNeuter(array.buffer);
|
||||
assertFalse(Array.prototype.includes.call(array, 0));
|
||||
assertFalse(Array.prototype.includes.call(array, 0, 10));
|
||||
},
|
||||
|
||||
Int16Array() {
|
||||
var array = new Int16Array([-32769, 32768,
|
||||
NaN /* 0 */, Infinity /* 0 */,
|
||||
-Infinity /* 0 */, -0 /* 0 */, +0 /* 0 */,
|
||||
0x7FFFF /* -1 */, 30000 /* 30000 */,
|
||||
300000 /* -27680 */]);
|
||||
assertFalse(Array.prototype.includes.call(array, -32769));
|
||||
assertFalse(Array.prototype.includes.call(array, 32768));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 2));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 3));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 4));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 5));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 6));
|
||||
assertFalse(Array.prototype.includes.call(array, 0, 7));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, -1, 7));
|
||||
assertFalse(Array.prototype.includes.call(array, -1, 8));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 30000, 8));
|
||||
assertFalse(Array.prototype.includes.call(array, 30000, 9));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, -27680, 9));
|
||||
},
|
||||
|
||||
Detached_Int16Array() {
|
||||
var array = new Int16Array(10);
|
||||
%ArrayBufferNeuter(array.buffer);
|
||||
assertFalse(Array.prototype.includes.call(array, 0));
|
||||
assertFalse(Array.prototype.includes.call(array, 0, 10));
|
||||
},
|
||||
|
||||
Uint16Array() {
|
||||
var array = new Uint16Array([-1, 65536,
|
||||
NaN /* 0 */, Infinity /* 0 */,
|
||||
-Infinity /* 0 */, -0 /* 0 */, +0 /* 0 */,
|
||||
0x7FFFF /* 65535 */, 300000 /* 37856 */,
|
||||
3000000 /* 50880 */]);
|
||||
assertFalse(Array.prototype.includes.call(array, -1));
|
||||
assertFalse(Array.prototype.includes.call(array, 65536));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 2));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 3));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 4));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 5));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 6));
|
||||
assertFalse(Array.prototype.includes.call(array, 0, 7));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 65535, 7));
|
||||
assertFalse(Array.prototype.includes.call(array, 65535, 8));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 37856, 8));
|
||||
assertFalse(Array.prototype.includes.call(array, 37856, 9));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 50880, 9));
|
||||
},
|
||||
|
||||
Detached_Uint16Array() {
|
||||
var array = new Uint16Array(10);
|
||||
%ArrayBufferNeuter(array.buffer);
|
||||
assertFalse(Array.prototype.includes.call(array, 0));
|
||||
assertFalse(Array.prototype.includes.call(array, 0, 10));
|
||||
},
|
||||
|
||||
Int32Array() {
|
||||
var array = new Int32Array([-2147483649, 2147483648,
|
||||
NaN /* 0 */, Infinity /* 0 */,
|
||||
-Infinity /* 0 */, -0 /* 0 */, +0 /* 0 */,
|
||||
0x7FFFFFFFF /* -1 */, 4294968064 /* 768 */,
|
||||
4294959447 /* -7849 */]);
|
||||
assertFalse(Array.prototype.includes.call(array, -2147483649));
|
||||
assertFalse(Array.prototype.includes.call(array, 2147483648));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 0.0, 2));
|
||||
assertTrue(Array.prototype.includes.call(array, 0.0, 3));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 4));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 5));
|
||||
assertTrue(Array.prototype.includes.call(array, 0.0, 6));
|
||||
assertFalse(Array.prototype.includes.call(array, 0.0, 7));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, -1, 7));
|
||||
assertFalse(Array.prototype.includes.call(array, -1, 8));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 768, 8));
|
||||
assertFalse(Array.prototype.includes.call(array, 768, 9));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, -7849, 9));
|
||||
},
|
||||
|
||||
Detached_Int32Array() {
|
||||
var array = new Int32Array(10);
|
||||
%ArrayBufferNeuter(array.buffer);
|
||||
assertFalse(Array.prototype.includes.call(array, 0));
|
||||
assertFalse(Array.prototype.includes.call(array, 0, 10));
|
||||
},
|
||||
|
||||
Uint32Array() {
|
||||
var array = new Uint32Array([-1, 4294967296,
|
||||
NaN /* 0 */, Infinity /* 0 */,
|
||||
-Infinity /* 0 */, -0 /* 0 */, +0 /* 0 */,
|
||||
0x7FFFFFFFF /* 4294967295 */,
|
||||
4294968064 /* 768 */,
|
||||
4295079447 /* 112151 */]);
|
||||
assertFalse(Array.prototype.includes.call(array, -1));
|
||||
assertFalse(Array.prototype.includes.call(array, 4294967296));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 0.0, 2));
|
||||
assertTrue(Array.prototype.includes.call(array, 0.0, 3));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 4));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 5));
|
||||
assertTrue(Array.prototype.includes.call(array, 0.0, 6));
|
||||
assertFalse(Array.prototype.includes.call(array, 0.0, 7));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 4294967295, 7));
|
||||
assertFalse(Array.prototype.includes.call(array, 4294967295, 8));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 768, 8));
|
||||
assertFalse(Array.prototype.includes.call(array, 768, 9));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 112151, 9));
|
||||
},
|
||||
|
||||
Detached_Uint32Array() {
|
||||
var array = new Uint32Array(10);
|
||||
%ArrayBufferNeuter(array.buffer);
|
||||
assertFalse(Array.prototype.includes.call(array, 0));
|
||||
assertFalse(Array.prototype.includes.call(array, 0, 10));
|
||||
},
|
||||
|
||||
Float32Array() {
|
||||
var array = new Float32Array([-1, 4294967296,
|
||||
NaN, Infinity /* 0 */,
|
||||
-Infinity /* 0 */, -0 /* 0 */, +0 /* 0 */,
|
||||
0x7FFFFFFFF /* 34359738368.0 */,
|
||||
-4294968064 /* -4294968320.0 */,
|
||||
4295079447 /* 4295079424.0 */]);
|
||||
assertTrue(Array.prototype.includes.call(array, -1.0));
|
||||
assertTrue(Array.prototype.includes.call(array, 4294967296));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, NaN, 2));
|
||||
assertTrue(Array.prototype.includes.call(array, Infinity, 3));
|
||||
assertTrue(Array.prototype.includes.call(array, -Infinity, 4));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 5));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 6));
|
||||
assertFalse(Array.prototype.includes.call(array, 0.0, 7));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 34359738368.0, 7));
|
||||
assertFalse(Array.prototype.includes.call(array, 34359738368.0, 8));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, -4294968320.0, 8));
|
||||
assertFalse(Array.prototype.includes.call(array, -4294968320.0, 9));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 4295079424.0, 9));
|
||||
},
|
||||
|
||||
Detached_Float32Array() {
|
||||
var array = new Float32Array(10);
|
||||
%ArrayBufferNeuter(array.buffer);
|
||||
assertFalse(Array.prototype.includes.call(array, 0));
|
||||
assertFalse(Array.prototype.includes.call(array, 0, 10));
|
||||
},
|
||||
|
||||
Float64Array() {
|
||||
var array = new Float64Array([-1, 4294967296,
|
||||
NaN, Infinity /* 0 */,
|
||||
-Infinity /* 0 */, -0 /* 0 */, +0 /* 0 */,
|
||||
0x7FFFFFFFF /* 34359738367.0 */,
|
||||
-4294968064 /* -4294968064.0 */,
|
||||
4295079447 /* 4295079447.0 */]);
|
||||
assertTrue(Array.prototype.includes.call(array, -1.0));
|
||||
assertTrue(Array.prototype.includes.call(array, 4294967296));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, NaN, 2));
|
||||
assertTrue(Array.prototype.includes.call(array, Infinity, 3));
|
||||
assertTrue(Array.prototype.includes.call(array, -Infinity, 4));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 5));
|
||||
assertTrue(Array.prototype.includes.call(array, 0, 6));
|
||||
assertFalse(Array.prototype.includes.call(array, 0.0, 7));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 34359738367.0, 7));
|
||||
assertFalse(Array.prototype.includes.call(array, 34359738367.0, 8));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, -4294968064.0, 8));
|
||||
assertFalse(Array.prototype.includes.call(array, -4294968064.0, 9));
|
||||
|
||||
assertTrue(Array.prototype.includes.call(array, 4295079447.0, 9));
|
||||
},
|
||||
|
||||
Detached_Float64Array() {
|
||||
var array = new Float32Array(10);
|
||||
%ArrayBufferNeuter(array.buffer);
|
||||
assertFalse(Array.prototype.includes.call(array, 0));
|
||||
assertFalse(Array.prototype.includes.call(array, 0, 10));
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
function runSuites(suites) {
|
||||
Object.keys(suites).forEach(suite => runSuite(suites[suite]));
|
||||
|
||||
function runSuite(suite) {
|
||||
Object.keys(suite).forEach(test => suite[test]());
|
||||
}
|
||||
}
|
||||
|
||||
runSuites(kTests);
|
Loading…
Reference in New Issue
Block a user