From c98f3a98d76acc484e0aec2bea7888795e92010e Mon Sep 17 00:00:00 2001 From: machenbach Date: Mon, 1 Aug 2016 23:52:28 -0700 Subject: [PATCH] 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} --- src/builtins/builtins-array.cc | 500 +-------------- src/builtins/builtins.h | 2 - src/code-stub-assembler.cc | 210 ------- src/code-stub-assembler.h | 16 - src/code-stubs.cc | 74 ++- src/compiler/code-assembler.cc | 2 +- src/compiler/code-assembler.h | 2 +- src/compiler/raw-machine-assembler.cc | 3 +- src/compiler/raw-machine-assembler.h | 5 +- src/elements.cc | 378 +----------- src/elements.h | 6 - src/factory.h | 10 - src/js/array.js | 44 +- src/js/typedarray.js | 26 +- src/objects-inl.h | 14 - src/objects.h | 3 - src/runtime/runtime-array.cc | 108 +--- src/runtime/runtime.h | 3 +- test/mjsunit/es7/array-includes-receiver.js | 634 -------------------- 19 files changed, 153 insertions(+), 1887 deletions(-) delete mode 100644 test/mjsunit/es7/array-includes-receiver.js diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc index 888eaef280..40a5b07c78 100644 --- a/src/builtins/builtins-array.cc +++ b/src/builtins/builtins-array.cc @@ -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 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(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 diff --git a/src/builtins/builtins.h b/src/builtins/builtins.h index 6ed4e13717..113ba1f883 100644 --- a/src/builtins/builtins.h +++ b/src/builtins/builtins.h @@ -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) \ diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc index 0e09499f0a..23e78b6e74 100644 --- a/src/code-stub-assembler.cc +++ b/src/code-stub-assembler.cc @@ -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(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, diff --git a/src/code-stub-assembler.h b/src/code-stub-assembler.h index c426b1ad2a..39aa95bfb5 100644 --- a/src/code-stub-assembler.h +++ b/src/code-stub-assembler.h @@ -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()); diff --git a/src/code-stubs.cc b/src/code-stubs.cc index d9b1343c87..71b1b8f6d7 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -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 diff --git a/src/compiler/code-assembler.cc b/src/compiler/code-assembler.cc index 0883fc18e8..0a81481d42 100644 --- a/src/compiler/code-assembler.cc +++ b/src/compiler/code-assembler.cc @@ -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)) diff --git a/src/compiler/code-assembler.h b/src/compiler/code-assembler.h index f648c372e7..d0de46e69c 100644 --- a/src/compiler/code-assembler.h +++ b/src/compiler/code-assembler.h @@ -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, diff --git a/src/compiler/raw-machine-assembler.cc b/src/compiler/raw-machine-assembler.cc index 8fd8b5c763..744a68f485 100644 --- a/src/compiler/raw-machine-assembler.cc +++ b/src/compiler/raw-machine-assembler.cc @@ -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_); diff --git a/src/compiler/raw-machine-assembler.h b/src/compiler/raw-machine-assembler.h index b167a73c3e..62b31ccb55 100644 --- a/src/compiler/raw-machine-assembler.h +++ b/src/compiler/raw-machine-assembler.h @@ -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); diff --git a/src/elements.cc b/src/elements.cc index 20e358848a..7db641649f 100644 --- a/src/elements.cc +++ b/src/elements.cc @@ -468,27 +468,6 @@ static void SortIndices( } } -static Maybe IncludesValueSlowPath(Isolate* isolate, - Handle receiver, - Handle 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 element_k; - ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k, - Object::GetProperty(&it), Nothing()); - - 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 IncludesValueImpl(Isolate* isolate, - Handle receiver, - Handle value, - uint32_t start_from, uint32_t length) { - return IncludesValueSlowPath(isolate, receiver, value, start_from, length); - } - - Maybe IncludesValue(Isolate* isolate, Handle receiver, - Handle 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 receiver, - Handle value, uint32_t start_from, - uint32_t length, Maybe* 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 IncludesValueImpl(Isolate* isolate, - Handle receiver, - Handle 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 result = Nothing(); - if (DictionaryElementsAccessor::IncludesValueFastPath( - isolate, receiver, value, start_from, length, &result)) { - return result; - } - } - - Handle 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 element_k; - - ASSIGN_RETURN_ON_EXCEPTION_VALUE( - isolate, element_k, JSObject::GetPropertyWithAccessor(&it), - Nothing()); - - 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 { } } - static Maybe IncludesValueImpl(Isolate* isolate, - Handle receiver, - Handle 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(elements_base->length()) < length) { - return Just(true); - } - - if (start_from >= length) return Just(false); - - length = std::min(static_cast(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 receiver, @@ -2406,17 +2125,17 @@ class FastHoleyDoubleElementsAccessor // Super class for all external element arrays. -template +template class TypedElementsAccessor - : public ElementsAccessorBase, - ElementsKindTraits> { + : public ElementsAccessorBase, + ElementsKindTraits > { public: explicit TypedElementsAccessor(const char* name) : ElementsAccessorBase >(name) {} typedef typename ElementsKindTraits::BackingStore BackingStore; - typedef TypedElementsAccessor AccessorClass; + typedef TypedElementsAccessor AccessorClass; static inline void SetImpl(Handle holder, uint32_t entry, Object* value) { @@ -2522,53 +2241,12 @@ class TypedElementsAccessor *nof_items = count; return Just(true); } - - static Maybe IncludesValueImpl(Isolate* isolate, - Handle receiver, - Handle 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(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::lowest() || - search_value > std::numeric_limits::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 \ + + +#define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \ + typedef TypedElementsAccessor \ 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 IncludesValueImpl(Isolate* isolate, - Handle object, - Handle value, - uint32_t start_from, uint32_t length) { - DCHECK(JSObject::PrototypeHasNoElements(isolate, *object)); - Handle 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 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()); - - 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); - } }; diff --git a/src/elements.h b/src/elements.h index a2fb0352ca..ae48d4ef07 100644 --- a/src/elements.h +++ b/src/elements.h @@ -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 IncludesValue(Isolate* isolate, Handle receiver, - Handle value, uint32_t start, - uint32_t length) = 0; - protected: friend class LookupIterator; diff --git a/src/factory.h b/src/factory.h index 4908d5fad8..98472ba0b8 100644 --- a/src/factory.h +++ b/src/factory.h @@ -380,16 +380,6 @@ class Factory final { } return NewNumber(static_cast(value), pretenure); } - Handle NewNumberFromInt64(int64_t value, - PretenureFlag pretenure = NOT_TENURED) { - if (value <= std::numeric_limits::max() && - value >= std::numeric_limits::min() && - Smi::IsValid(static_cast(value))) { - return Handle(Smi::FromInt(static_cast(value)), - isolate()); - } - return NewNumber(static_cast(value), pretenure); - } Handle NewHeapNumber(double value, MutableMode mode = IMMUTABLE, PretenureFlag pretenure = NOT_TENURED); diff --git a/src/js/array.js b/src/js/array.js index 8fe319e7ad..c28f96e8d9 100644 --- a/src/js/array.js +++ b/src/js/array.js @@ -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; diff --git a/src/js/typedarray.js b/src/js/typedarray.js index 15bc729662..8e7d9ee77e 100644 --- a/src/js/typedarray.js +++ b/src/js/typedarray.js @@ -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); diff --git a/src/objects-inl.h b/src/objects-inl.h index 9ac35fd1cf..a7795a6c37 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -1144,20 +1144,6 @@ MUST_USE_RESULT MaybeHandle 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(p) + offset - kHeapObjectTag) diff --git a/src/objects.h b/src/objects.h index 6b71debd4b..a9c2439e61 100644 --- a/src/objects.h +++ b/src/objects.h @@ -2210,9 +2210,6 @@ class JSObject: public JSReceiver { static bool UnregisterPrototypeUser(Handle 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: diff --git a/src/runtime/runtime-array.cc b/src/runtime/runtime-array.cc index 0f9f91991d..0473b76246 100644 --- a/src/runtime/runtime-array.cc +++ b/src/runtime/runtime-array.cc @@ -32,24 +32,18 @@ RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) { } static void InstallCode(Isolate* isolate, Handle holder, - const char* name, Handle code, int argc = -1) { + const char* name, Handle code) { Handle key = isolate->factory()->InternalizeUtf8String(name); Handle optimized = isolate->factory()->NewFunctionWithoutPrototype(key, code); - if (argc < 0) { - optimized->shared()->DontAdaptArguments(); - } else { - optimized->shared()->set_internal_formal_parameter_count(argc); - } + optimized->shared()->DontAdaptArguments(); JSObject::AddProperty(holder, key, optimized, NONE); } static void InstallBuiltin(Isolate* isolate, Handle 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 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 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(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(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 obj = Handle::cast(object); - ElementsAccessor* elements = obj->GetElementsAccessor(); - Maybe result = elements->IncludesValue(isolate, obj, search_element, - static_cast(index), - static_cast(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 element_k; - { - Handle 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 diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index f1afbe88a0..3e5ee18d2a 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -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) \ diff --git a/test/mjsunit/es7/array-includes-receiver.js b/test/mjsunit/es7/array-includes-receiver.js deleted file mode 100644 index 85915d4958..0000000000 --- a/test/mjsunit/es7/array-includes-receiver.js +++ /dev/null @@ -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);