Index: src/builtins/builtins-array.cc |
diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc |
index 888eaef280f821e723435327f1116e4203de86b5..40a5b07c78a6da2c2191bfca70fdbe957bf627aa 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 @@ |
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 @@ |
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 @@ |
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 |