Index: src/builtins/builtins-array.cc |
diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc |
index 2916cff23d2cf9b767a0f072156fa6829fc9603f..c565fff1cd0c9770e136057002450b7e2ebdbd47 100644 |
--- a/src/builtins/builtins-array.cc |
+++ b/src/builtins/builtins-array.cc |
@@ -188,160 +188,6 @@ BUILTIN(ArrayPush) { |
return Smi::FromInt(new_length); |
} |
-TF_BUILTIN(FastArrayPush, CodeStubAssembler) { |
- Variable arg_index(this, MachineType::PointerRepresentation()); |
- Label default_label(this, &arg_index); |
- Label smi_transition(this); |
- Label object_push_pre(this); |
- Label object_push(this, &arg_index); |
- Label double_push(this, &arg_index); |
- Label double_transition(this); |
- Label runtime(this, Label::kDeferred); |
- |
- Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount); |
- Node* context = Parameter(BuiltinDescriptor::kContext); |
- Node* new_target = Parameter(BuiltinDescriptor::kNewTarget); |
- |
- CodeStubArguments args(this, ChangeInt32ToIntPtr(argc)); |
- Node* receiver = args.GetReceiver(); |
- Node* kind = nullptr; |
- |
- Label fast(this); |
- BranchIfFastJSArray(receiver, context, FastJSArrayAccessMode::ANY_ACCESS, |
- &fast, &runtime); |
- |
- Bind(&fast); |
- { |
- // Disallow pushing onto prototypes. It might be the JSArray prototype. |
- // Disallow pushing onto non-extensible objects. |
- Comment("Disallow pushing onto prototypes"); |
- Node* map = LoadMap(receiver); |
- Node* bit_field2 = LoadMapBitField2(map); |
- int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) | |
- (1 << Map::kIsExtensible); |
- Node* test = Word32And(bit_field2, Int32Constant(mask)); |
- GotoIf(Word32NotEqual(test, Int32Constant(1 << Map::kIsExtensible)), |
- &runtime); |
- |
- // Disallow pushing onto arrays in dictionary named property mode. We need |
- // to figure out whether the length property is still writable. |
- Comment("Disallow pushing onto arrays in dictionary named property mode"); |
- GotoIf(IsDictionaryMap(map), &runtime); |
- |
- // Check whether the length property is writable. The length property is the |
- // only default named property on arrays. It's nonconfigurable, hence is |
- // guaranteed to stay the first property. |
- Node* descriptors = LoadMapDescriptors(map); |
- Node* details = |
- LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0)); |
- GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask), |
- &runtime); |
- |
- arg_index.Bind(IntPtrConstant(0)); |
- kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); |
- |
- GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)), |
- &object_push_pre); |
- |
- Node* new_length = BuildAppendJSArray(FAST_SMI_ELEMENTS, context, receiver, |
- args, arg_index, &smi_transition); |
- args.PopAndReturn(new_length); |
- } |
- |
- // If the argument is not a smi, then use a heavyweight SetProperty to |
- // transition the array for only the single next element. If the argument is |
- // a smi, the failure is due to some other reason and we should fall back on |
- // the most generic implementation for the rest of the array. |
- Bind(&smi_transition); |
- { |
- Node* arg = args.AtIndex(arg_index.value()); |
- GotoIf(TaggedIsSmi(arg), &default_label); |
- Node* length = LoadJSArrayLength(receiver); |
- // TODO(danno): Use the KeyedStoreGeneric stub here when possible, |
- // calling into the runtime to do the elements transition is overkill. |
- CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, |
- SmiConstant(STRICT)); |
- Increment(arg_index); |
- // The runtime SetProperty call could have converted the array to dictionary |
- // mode, which must be detected to abort the fast-path. |
- Node* map = LoadMap(receiver); |
- Node* bit_field2 = LoadMapBitField2(map); |
- Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); |
- GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)), |
- &default_label); |
- |
- GotoIfNotNumber(arg, &object_push); |
- Goto(&double_push); |
- } |
- |
- Bind(&object_push_pre); |
- { |
- Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), |
- &double_push, &object_push); |
- } |
- |
- Bind(&object_push); |
- { |
- Node* new_length = BuildAppendJSArray(FAST_ELEMENTS, context, receiver, |
- args, arg_index, &default_label); |
- args.PopAndReturn(new_length); |
- } |
- |
- Bind(&double_push); |
- { |
- Node* new_length = |
- BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver, args, |
- arg_index, &double_transition); |
- args.PopAndReturn(new_length); |
- } |
- |
- // If the argument is not a double, then use a heavyweight SetProperty to |
- // transition the array for only the single next element. If the argument is |
- // a double, the failure is due to some other reason and we should fall back |
- // on the most generic implementation for the rest of the array. |
- Bind(&double_transition); |
- { |
- Node* arg = args.AtIndex(arg_index.value()); |
- GotoIfNumber(arg, &default_label); |
- Node* length = LoadJSArrayLength(receiver); |
- // TODO(danno): Use the KeyedStoreGeneric stub here when possible, |
- // calling into the runtime to do the elements transition is overkill. |
- CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, |
- SmiConstant(STRICT)); |
- Increment(arg_index); |
- // The runtime SetProperty call could have converted the array to dictionary |
- // mode, which must be detected to abort the fast-path. |
- Node* map = LoadMap(receiver); |
- Node* bit_field2 = LoadMapBitField2(map); |
- Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); |
- GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)), |
- &default_label); |
- Goto(&object_push); |
- } |
- |
- // Fallback that stores un-processed arguments using the full, heavyweight |
- // SetProperty machinery. |
- Bind(&default_label); |
- { |
- args.ForEach( |
- [this, receiver, context](Node* arg) { |
- Node* length = LoadJSArrayLength(receiver); |
- CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, |
- SmiConstant(STRICT)); |
- }, |
- arg_index.value()); |
- args.PopAndReturn(LoadJSArrayLength(receiver)); |
- } |
- |
- Bind(&runtime); |
- { |
- Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, |
- MachineType::TaggedPointer()); |
- TailCallStub(CodeFactory::ArrayPush(isolate()), context, target, new_target, |
- argc); |
- } |
-} |
- |
BUILTIN(ArrayPop) { |
HandleScope scope(isolate); |
Handle<Object> receiver = args.receiver(); |
@@ -415,305 +261,6 @@ BUILTIN(ArrayUnshift) { |
return Smi::FromInt(new_length); |
} |
-class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
- public: |
- explicit ArrayBuiltinCodeStubAssembler(compiler::CodeAssemblerState* state) |
- : CodeStubAssembler(state) {} |
- |
- typedef std::function<Node*(Node* o, Node* len)> BuiltinResultGenerator; |
- typedef std::function<void(Node* a, Node* pK, Node* value)> |
- CallResultProcessor; |
- |
- void GenerateArrayIteratingBuiltinBody( |
- const char* name, Node* receiver, Node* callbackfn, Node* this_arg, |
- Node* context, const BuiltinResultGenerator& generator, |
- const CallResultProcessor& processor) { |
- Variable k(this, MachineRepresentation::kTagged, SmiConstant(0)); |
- Label non_array(this), slow(this, &k), array_changes(this, &k); |
- |
- // TODO(danno): Seriously? Do we really need to throw the exact error |
- // message on null and undefined so that the webkit tests pass? |
- Label throw_null_undefined_exception(this, Label::kDeferred); |
- GotoIf(WordEqual(receiver, NullConstant()), |
- &throw_null_undefined_exception); |
- GotoIf(WordEqual(receiver, UndefinedConstant()), |
- &throw_null_undefined_exception); |
- |
- // By the book: taken directly from the ECMAScript 2015 specification |
- |
- // 1. Let O be ToObject(this value). |
- // 2. ReturnIfAbrupt(O) |
- Node* o = CallStub(CodeFactory::ToObject(isolate()), context, receiver); |
- |
- // 3. Let len be ToLength(Get(O, "length")). |
- // 4. ReturnIfAbrupt(len). |
- Variable merged_length(this, MachineRepresentation::kTagged); |
- Label has_length(this, &merged_length), not_js_array(this); |
- GotoIf(DoesntHaveInstanceType(o, JS_ARRAY_TYPE), ¬_js_array); |
- merged_length.Bind(LoadJSArrayLength(o)); |
- Goto(&has_length); |
- Bind(¬_js_array); |
- Node* len_property = |
- GetProperty(context, o, isolate()->factory()->length_string()); |
- merged_length.Bind( |
- CallStub(CodeFactory::ToLength(isolate()), context, len_property)); |
- Goto(&has_length); |
- Bind(&has_length); |
- Node* len = merged_length.value(); |
- |
- // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. |
- Label type_exception(this, Label::kDeferred); |
- Label done(this); |
- GotoIf(TaggedIsSmi(callbackfn), &type_exception); |
- Branch(IsCallableMap(LoadMap(callbackfn)), &done, &type_exception); |
- |
- Bind(&throw_null_undefined_exception); |
- { |
- CallRuntime( |
- Runtime::kThrowTypeError, context, |
- SmiConstant(MessageTemplate::kCalledOnNullOrUndefined), |
- HeapConstant(isolate()->factory()->NewStringFromAsciiChecked(name))); |
- Unreachable(); |
- } |
- |
- Bind(&type_exception); |
- { |
- CallRuntime(Runtime::kThrowTypeError, context, |
- SmiConstant(MessageTemplate::kCalledNonCallable), callbackfn); |
- Unreachable(); |
- } |
- |
- Bind(&done); |
- |
- Node* a = generator(o, len); |
- |
- // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. |
- // [Already done by the arguments adapter] |
- |
- HandleFastElements(context, this_arg, o, len, callbackfn, processor, a, k, |
- &slow); |
- |
- // 7. Let k be 0. |
- // Already done above in initialization of the Variable k |
- |
- Bind(&slow); |
- { |
- // 8. Repeat, while k < len |
- Label loop(this, &k); |
- Label after_loop(this); |
- Goto(&loop); |
- Bind(&loop); |
- { |
- GotoUnlessNumberLessThan(k.value(), len, &after_loop); |
- |
- Label done_element(this); |
- // a. Let Pk be ToString(k). |
- Node* p_k = ToString(context, k.value()); |
- |
- // b. Let kPresent be HasProperty(O, Pk). |
- // c. ReturnIfAbrupt(kPresent). |
- Node* k_present = |
- CallStub(CodeFactory::HasProperty(isolate()), context, p_k, o); |
- |
- // d. If kPresent is true, then |
- GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); |
- |
- // i. Let kValue be Get(O, Pk). |
- // ii. ReturnIfAbrupt(kValue). |
- Node* k_value = GetProperty(context, o, k.value()); |
- |
- // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). |
- // iv. ReturnIfAbrupt(funcResult). |
- Node* result = CallJS(CodeFactory::Call(isolate()), context, callbackfn, |
- this_arg, k_value, k.value(), o); |
- |
- processor(a, p_k, result); |
- Goto(&done_element); |
- Bind(&done_element); |
- |
- // e. Increase k by 1. |
- k.Bind(NumberInc(k.value())); |
- Goto(&loop); |
- } |
- Bind(&after_loop); |
- Return(a); |
- } |
- } |
- |
- private: |
- Node* VisitAllFastElementsOneKind(Node* context, ElementsKind kind, |
- Node* this_arg, Node* o, Node* len, |
- Node* callbackfn, |
- const CallResultProcessor& processor, |
- Node* a, Label* array_changed, |
- ParameterMode mode) { |
- Comment("begin VisitAllFastElementsOneKind"); |
- Variable original_map(this, MachineRepresentation::kTagged); |
- original_map.Bind(LoadMap(o)); |
- VariableList list({&original_map}, zone()); |
- Node* last_index = nullptr; |
- BuildFastLoop( |
- list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode), |
- [=, &original_map, &last_index](Node* index) { |
- last_index = index; |
- Label one_element_done(this), hole_element(this); |
- |
- // Check if o's map has changed during the callback. If so, we have to |
- // fall back to the slower spec implementation for the rest of the |
- // iteration. |
- Node* o_map = LoadMap(o); |
- GotoIf(WordNotEqual(o_map, original_map.value()), array_changed); |
- |
- // Check if o's length has changed during the callback and if the |
- // index is now out of range of the new length. |
- Node* tagged_index = ParameterToTagged(index, mode); |
- GotoIf(SmiGreaterThanOrEqual(tagged_index, LoadJSArrayLength(o)), |
- array_changed); |
- |
- // Re-load the elements array. If may have been resized. |
- Node* elements = LoadElements(o); |
- |
- // Fast case: load the element directly from the elements FixedArray |
- // and call the callback if the element is not the hole. |
- DCHECK(kind == FAST_ELEMENTS || kind == FAST_DOUBLE_ELEMENTS); |
- int base_size = kind == FAST_ELEMENTS |
- ? FixedArray::kHeaderSize |
- : (FixedArray::kHeaderSize - kHeapObjectTag); |
- Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); |
- Node* value = nullptr; |
- if (kind == FAST_ELEMENTS) { |
- value = LoadObjectField(elements, offset); |
- GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); |
- } else { |
- Node* double_value = |
- LoadDoubleWithHoleCheck(elements, offset, &hole_element); |
- value = AllocateHeapNumberWithValue(double_value); |
- } |
- Node* result = CallJS(CodeFactory::Call(isolate()), context, |
- callbackfn, this_arg, value, tagged_index, o); |
- processor(a, tagged_index, result); |
- Goto(&one_element_done); |
- |
- Bind(&hole_element); |
- // Check if o's prototype change unexpectedly has elements after the |
- // callback in the case of a hole. |
- BranchIfPrototypesHaveNoElements(o_map, &one_element_done, |
- array_changed); |
- |
- Bind(&one_element_done); |
- }, |
- 1, mode, IndexAdvanceMode::kPost); |
- Comment("end VisitAllFastElementsOneKind"); |
- return last_index; |
- } |
- |
- void HandleFastElements(Node* context, Node* this_arg, Node* o, Node* len, |
- Node* callbackfn, CallResultProcessor processor, |
- Node* a, Variable& k, Label* slow) { |
- Label switch_on_elements_kind(this), fast_elements(this), |
- maybe_double_elements(this), fast_double_elements(this); |
- |
- Comment("begin HandleFastElements"); |
- // Non-smi lengths must use the slow path. |
- GotoIf(TaggedIsNotSmi(len), slow); |
- |
- BranchIfFastJSArray(o, context, |
- CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, |
- &switch_on_elements_kind, slow); |
- |
- Bind(&switch_on_elements_kind); |
- // Select by ElementsKind |
- Node* o_map = LoadMap(o); |
- Node* bit_field2 = LoadMapBitField2(o_map); |
- Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); |
- Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), |
- &maybe_double_elements, &fast_elements); |
- |
- ParameterMode mode = OptimalParameterMode(); |
- Bind(&fast_elements); |
- { |
- Label array_changed(this, Label::kDeferred); |
- Node* last_index = VisitAllFastElementsOneKind( |
- context, FAST_ELEMENTS, this_arg, o, len, callbackfn, processor, a, |
- &array_changed, mode); |
- |
- // No exception, return success |
- Return(a); |
- |
- Bind(&array_changed); |
- k.Bind(ParameterToTagged(last_index, mode)); |
- Goto(slow); |
- } |
- |
- Bind(&maybe_double_elements); |
- Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)), |
- slow, &fast_double_elements); |
- |
- Bind(&fast_double_elements); |
- { |
- Label array_changed(this, Label::kDeferred); |
- Node* last_index = VisitAllFastElementsOneKind( |
- context, FAST_DOUBLE_ELEMENTS, this_arg, o, len, callbackfn, |
- processor, a, &array_changed, mode); |
- |
- // No exception, return success |
- Return(a); |
- |
- Bind(&array_changed); |
- k.Bind(ParameterToTagged(last_index, mode)); |
- Goto(slow); |
- } |
- } |
-}; |
- |
-TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) { |
- Node* receiver = Parameter(ForEachDescriptor::kReceiver); |
- Node* callbackfn = Parameter(ForEachDescriptor::kCallback); |
- Node* this_arg = Parameter(ForEachDescriptor::kThisArg); |
- Node* context = Parameter(ForEachDescriptor::kContext); |
- |
- GenerateArrayIteratingBuiltinBody( |
- "Array.prototype.forEach", receiver, callbackfn, this_arg, context, |
- [=](Node*, Node*) { return UndefinedConstant(); }, |
- [](Node* a, Node* p_k, Node* value) {}); |
-} |
- |
-TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) { |
- Node* receiver = Parameter(ForEachDescriptor::kReceiver); |
- Node* callbackfn = Parameter(ForEachDescriptor::kCallback); |
- Node* this_arg = Parameter(ForEachDescriptor::kThisArg); |
- Node* context = Parameter(ForEachDescriptor::kContext); |
- |
- GenerateArrayIteratingBuiltinBody( |
- "Array.prototype.every", receiver, callbackfn, this_arg, context, |
- [=](Node*, Node*) { return TrueConstant(); }, |
- [=](Node* a, Node* p_k, Node* value) { |
- Label true_continue(this), return_false(this); |
- BranchIfToBooleanIsTrue(value, &true_continue, &return_false); |
- Bind(&return_false); |
- Return(FalseConstant()); |
- Bind(&true_continue); |
- }); |
-} |
- |
-TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) { |
- Node* receiver = Parameter(ForEachDescriptor::kReceiver); |
- Node* callbackfn = Parameter(ForEachDescriptor::kCallback); |
- Node* this_arg = Parameter(ForEachDescriptor::kThisArg); |
- Node* context = Parameter(ForEachDescriptor::kContext); |
- |
- GenerateArrayIteratingBuiltinBody( |
- "Array.prototype.some", receiver, callbackfn, this_arg, context, |
- [=](Node*, Node*) { return FalseConstant(); }, |
- [=](Node* a, Node* p_k, Node* value) { |
- Label false_continue(this), return_true(this); |
- BranchIfToBooleanIsTrue(value, &return_true, &false_continue); |
- Bind(&return_true); |
- Return(TrueConstant()); |
- Bind(&false_continue); |
- }); |
-} |
- |
BUILTIN(ArraySlice) { |
HandleScope scope(isolate); |
Handle<Object> receiver = args.receiver(); |
@@ -1692,1057 +1239,5 @@ BUILTIN(ArrayConcat) { |
return Slow_ArrayConcat(&args, species, isolate); |
} |
-TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { |
- Node* object = Parameter(1); |
- Node* context = Parameter(4); |
- |
- Label call_runtime(this), return_true(this), return_false(this); |
- |
- GotoIf(TaggedIsSmi(object), &return_false); |
- Node* instance_type = LoadInstanceType(object); |
- |
- GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), |
- &return_true); |
- |
- // TODO(verwaest): Handle proxies in-place. |
- Branch(Word32Equal(instance_type, Int32Constant(JS_PROXY_TYPE)), |
- &call_runtime, &return_false); |
- |
- Bind(&return_true); |
- Return(BooleanConstant(true)); |
- |
- Bind(&return_false); |
- Return(BooleanConstant(false)); |
- |
- Bind(&call_runtime); |
- Return(CallRuntime(Runtime::kArrayIsArray, context, object)); |
-} |
- |
-TF_BUILTIN(ArrayIncludes, CodeStubAssembler) { |
- Node* const array = Parameter(0); |
- Node* const search_element = Parameter(1); |
- Node* const start_from = Parameter(2); |
- Node* const context = Parameter(3 + 2); |
- |
- Variable index_var(this, MachineType::PointerRepresentation()); |
- |
- Label init_k(this), return_true(this), return_false(this), call_runtime(this); |
- Label init_len(this), select_loop(this); |
- |
- index_var.Bind(IntPtrConstant(0)); |
- |
- // Take slow path if not a JSArray, if retrieving elements requires |
- // traversing prototype, or if access checks are required. |
- BranchIfFastJSArray(array, context, FastJSArrayAccessMode::INBOUNDS_READ, |
- &init_len, &call_runtime); |
- |
- Bind(&init_len); |
- // JSArray length is always an Smi for fast arrays. |
- CSA_ASSERT(this, TaggedIsSmi(LoadObjectField(array, JSArray::kLengthOffset))); |
- Node* const len = LoadAndUntagObjectField(array, JSArray::kLengthOffset); |
- |
- GotoIf(IsUndefined(start_from), &select_loop); |
- |
- // Bailout to slow path if startIndex is not an Smi. |
- Branch(TaggedIsSmi(start_from), &init_k, &call_runtime); |
- |
- Bind(&init_k); |
- CSA_ASSERT(this, TaggedIsSmi(start_from)); |
- Node* const untagged_start_from = SmiToWord(start_from); |
- index_var.Bind(Select( |
- IntPtrGreaterThanOrEqual(untagged_start_from, IntPtrConstant(0)), |
- [=]() { return untagged_start_from; }, |
- [=]() { |
- Node* const index = IntPtrAdd(len, untagged_start_from); |
- return SelectConstant(IntPtrLessThan(index, IntPtrConstant(0)), |
- IntPtrConstant(0), index, |
- MachineType::PointerRepresentation()); |
- }, |
- MachineType::PointerRepresentation())); |
- |
- Goto(&select_loop); |
- Bind(&select_loop); |
- 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(this), if_packed_doubles(this), if_holey_doubles(this); |
- Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects, |
- &if_smiorobjects, &if_smiorobjects, |
- &if_packed_doubles, &if_holey_doubles}; |
- |
- Node* map = LoadMap(array); |
- Node* elements_kind = LoadMapElementsKind(map); |
- Node* elements = LoadElements(array); |
- Switch(elements_kind, &return_false, kElementsKind, element_kind_handlers, |
- arraysize(kElementsKind)); |
- |
- Bind(&if_smiorobjects); |
- { |
- Variable search_num(this, MachineRepresentation::kFloat64); |
- Label ident_loop(this, &index_var), heap_num_loop(this, &search_num), |
- string_loop(this, &index_var), undef_loop(this, &index_var), |
- not_smi(this), not_heap_num(this); |
- |
- GotoIfNot(TaggedIsSmi(search_element), ¬_smi); |
- search_num.Bind(SmiToFloat64(search_element)); |
- Goto(&heap_num_loop); |
- |
- Bind(¬_smi); |
- GotoIf(WordEqual(search_element, UndefinedConstant()), &undef_loop); |
- Node* map = LoadMap(search_element); |
- GotoIfNot(IsHeapNumberMap(map), ¬_heap_num); |
- search_num.Bind(LoadHeapNumberValue(search_element)); |
- Goto(&heap_num_loop); |
- |
- Bind(¬_heap_num); |
- Node* search_type = LoadMapInstanceType(map); |
- GotoIf(IsStringInstanceType(search_type), &string_loop); |
- Goto(&ident_loop); |
- |
- Bind(&ident_loop); |
- { |
- GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); |
- Node* element_k = LoadFixedArrayElement(elements, index_var.value()); |
- GotoIf(WordEqual(element_k, search_element), &return_true); |
- |
- index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); |
- Goto(&ident_loop); |
- } |
- |
- Bind(&undef_loop); |
- { |
- GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); |
- Node* element_k = LoadFixedArrayElement(elements, index_var.value()); |
- GotoIf(WordEqual(element_k, UndefinedConstant()), &return_true); |
- GotoIf(WordEqual(element_k, TheHoleConstant()), &return_true); |
- |
- index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); |
- Goto(&undef_loop); |
- } |
- |
- Bind(&heap_num_loop); |
- { |
- Label nan_loop(this, &index_var), not_nan_loop(this, &index_var); |
- BranchIfFloat64IsNaN(search_num.value(), &nan_loop, ¬_nan_loop); |
- |
- Bind(¬_nan_loop); |
- { |
- Label continue_loop(this), not_smi(this); |
- GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); |
- Node* element_k = LoadFixedArrayElement(elements, index_var.value()); |
- GotoIfNot(TaggedIsSmi(element_k), ¬_smi); |
- Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)), |
- &return_true, &continue_loop); |
- |
- Bind(¬_smi); |
- GotoIfNot(IsHeapNumber(element_k), &continue_loop); |
- Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)), |
- &return_true, &continue_loop); |
- |
- Bind(&continue_loop); |
- index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); |
- Goto(¬_nan_loop); |
- } |
- |
- Bind(&nan_loop); |
- { |
- Label continue_loop(this); |
- GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); |
- Node* element_k = LoadFixedArrayElement(elements, index_var.value()); |
- GotoIf(TaggedIsSmi(element_k), &continue_loop); |
- GotoIfNot(IsHeapNumber(element_k), &continue_loop); |
- BranchIfFloat64IsNaN(LoadHeapNumberValue(element_k), &return_true, |
- &continue_loop); |
- |
- Bind(&continue_loop); |
- index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); |
- Goto(&nan_loop); |
- } |
- } |
- |
- Bind(&string_loop); |
- { |
- Label continue_loop(this); |
- GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); |
- Node* element_k = LoadFixedArrayElement(elements, index_var.value()); |
- GotoIf(TaggedIsSmi(element_k), &continue_loop); |
- GotoIfNot(IsStringInstanceType(LoadInstanceType(element_k)), |
- &continue_loop); |
- |
- // TODO(bmeurer): Consider inlining the StringEqual logic here. |
- Node* result = CallStub(CodeFactory::StringEqual(isolate()), context, |
- search_element, element_k); |
- Branch(WordEqual(BooleanConstant(true), result), &return_true, |
- &continue_loop); |
- |
- Bind(&continue_loop); |
- index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); |
- Goto(&string_loop); |
- } |
- } |
- |
- Bind(&if_packed_doubles); |
- { |
- Label nan_loop(this, &index_var), not_nan_loop(this, &index_var), |
- hole_loop(this, &index_var), search_notnan(this); |
- Variable search_num(this, MachineRepresentation::kFloat64); |
- |
- GotoIfNot(TaggedIsSmi(search_element), &search_notnan); |
- search_num.Bind(SmiToFloat64(search_element)); |
- Goto(¬_nan_loop); |
- |
- Bind(&search_notnan); |
- GotoIfNot(IsHeapNumber(search_element), &return_false); |
- |
- search_num.Bind(LoadHeapNumberValue(search_element)); |
- |
- BranchIfFloat64IsNaN(search_num.value(), &nan_loop, ¬_nan_loop); |
- |
- // Search for HeapNumber |
- Bind(¬_nan_loop); |
- { |
- Label continue_loop(this); |
- GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); |
- Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(), |
- MachineType::Float64()); |
- Branch(Float64Equal(element_k, search_num.value()), &return_true, |
- &continue_loop); |
- Bind(&continue_loop); |
- index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); |
- Goto(¬_nan_loop); |
- } |
- |
- // Search for NaN |
- Bind(&nan_loop); |
- { |
- Label continue_loop(this); |
- GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); |
- Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(), |
- MachineType::Float64()); |
- BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop); |
- Bind(&continue_loop); |
- index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); |
- Goto(&nan_loop); |
- } |
- } |
- |
- Bind(&if_holey_doubles); |
- { |
- Label nan_loop(this, &index_var), not_nan_loop(this, &index_var), |
- hole_loop(this, &index_var), search_notnan(this); |
- Variable search_num(this, MachineRepresentation::kFloat64); |
- |
- GotoIfNot(TaggedIsSmi(search_element), &search_notnan); |
- search_num.Bind(SmiToFloat64(search_element)); |
- Goto(¬_nan_loop); |
- |
- Bind(&search_notnan); |
- GotoIf(WordEqual(search_element, UndefinedConstant()), &hole_loop); |
- GotoIfNot(IsHeapNumber(search_element), &return_false); |
- |
- search_num.Bind(LoadHeapNumberValue(search_element)); |
- |
- BranchIfFloat64IsNaN(search_num.value(), &nan_loop, ¬_nan_loop); |
- |
- // Search for HeapNumber |
- Bind(¬_nan_loop); |
- { |
- Label continue_loop(this); |
- GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); |
- |
- // Load double value or continue if it contains a double hole. |
- Node* element_k = LoadFixedDoubleArrayElement( |
- elements, index_var.value(), MachineType::Float64(), 0, |
- INTPTR_PARAMETERS, &continue_loop); |
- |
- Branch(Float64Equal(element_k, search_num.value()), &return_true, |
- &continue_loop); |
- Bind(&continue_loop); |
- index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); |
- Goto(¬_nan_loop); |
- } |
- |
- // Search for NaN |
- Bind(&nan_loop); |
- { |
- Label continue_loop(this); |
- GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); |
- |
- // Load double value or continue if it contains a double hole. |
- Node* element_k = LoadFixedDoubleArrayElement( |
- elements, index_var.value(), MachineType::Float64(), 0, |
- INTPTR_PARAMETERS, &continue_loop); |
- |
- BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop); |
- Bind(&continue_loop); |
- index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); |
- Goto(&nan_loop); |
- } |
- |
- // Search for the Hole |
- Bind(&hole_loop); |
- { |
- GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); |
- |
- // Check if the element is a double hole, but don't load it. |
- LoadFixedDoubleArrayElement(elements, index_var.value(), |
- MachineType::None(), 0, INTPTR_PARAMETERS, |
- &return_true); |
- |
- index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); |
- Goto(&hole_loop); |
- } |
- } |
- |
- Bind(&return_true); |
- Return(TrueConstant()); |
- |
- Bind(&return_false); |
- Return(FalseConstant()); |
- |
- Bind(&call_runtime); |
- Return(CallRuntime(Runtime::kArrayIncludes_Slow, context, array, |
- search_element, start_from)); |
-} |
- |
-TF_BUILTIN(ArrayIndexOf, CodeStubAssembler) { |
- Node* array = Parameter(0); |
- Node* search_element = Parameter(1); |
- Node* start_from = Parameter(2); |
- Node* context = Parameter(3 + 2); |
- |
- Node* intptr_zero = IntPtrConstant(0); |
- Node* intptr_one = IntPtrConstant(1); |
- |
- Variable len_var(this, MachineType::PointerRepresentation()), |
- index_var(this, MachineType::PointerRepresentation()), |
- start_from_var(this, MachineType::PointerRepresentation()); |
- |
- Label init_k(this), return_found(this), return_not_found(this), |
- call_runtime(this); |
- |
- Label init_len(this); |
- |
- index_var.Bind(intptr_zero); |
- len_var.Bind(intptr_zero); |
- |
- // Take slow path if not a JSArray, if retrieving elements requires |
- // traversing prototype, or if access checks are required. |
- BranchIfFastJSArray(array, context, FastJSArrayAccessMode::INBOUNDS_READ, |
- &init_len, &call_runtime); |
- |
- Bind(&init_len); |
- { |
- // JSArray length is always an Smi for fast arrays. |
- CSA_ASSERT(this, |
- TaggedIsSmi(LoadObjectField(array, JSArray::kLengthOffset))); |
- Node* len = LoadAndUntagObjectField(array, JSArray::kLengthOffset); |
- |
- len_var.Bind(len); |
- Branch(WordEqual(len_var.value(), intptr_zero), &return_not_found, &init_k); |
- } |
- |
- Bind(&init_k); |
- { |
- // For now only deal with undefined and Smis here; we must be really careful |
- // with side-effects from the ToInteger conversion as the side-effects might |
- // render our assumptions about the receiver being a fast JSArray and the |
- // length invalid. |
- Label done(this), init_k_smi(this), init_k_other(this), init_k_zero(this), |
- init_k_n(this); |
- Branch(TaggedIsSmi(start_from), &init_k_smi, &init_k_other); |
- |
- Bind(&init_k_smi); |
- { |
- // The fromIndex is a Smi. |
- start_from_var.Bind(SmiUntag(start_from)); |
- Goto(&init_k_n); |
- } |
- |
- Bind(&init_k_other); |
- { |
- // The fromIndex must be undefined then, otherwise bailout and let the |
- // runtime deal with the full ToInteger conversion. |
- GotoIfNot(IsUndefined(start_from), &call_runtime); |
- start_from_var.Bind(intptr_zero); |
- Goto(&init_k_n); |
- } |
- |
- Bind(&init_k_n); |
- { |
- Label if_positive(this), if_negative(this), done(this); |
- Branch(IntPtrLessThan(start_from_var.value(), intptr_zero), &if_negative, |
- &if_positive); |
- |
- Bind(&if_positive); |
- { |
- index_var.Bind(start_from_var.value()); |
- Goto(&done); |
- } |
- |
- Bind(&if_negative); |
- { |
- index_var.Bind(IntPtrAdd(len_var.value(), start_from_var.value())); |
- Branch(IntPtrLessThan(index_var.value(), intptr_zero), &init_k_zero, |
- &done); |
- } |
- |
- Bind(&init_k_zero); |
- { |
- index_var.Bind(intptr_zero); |
- Goto(&done); |
- } |
- |
- 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(this), if_packed_doubles(this), if_holey_doubles(this); |
- Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects, |
- &if_smiorobjects, &if_smiorobjects, |
- &if_packed_doubles, &if_holey_doubles}; |
- |
- Node* map = LoadMap(array); |
- Node* elements_kind = LoadMapElementsKind(map); |
- Node* elements = LoadElements(array); |
- Switch(elements_kind, &return_not_found, kElementsKind, element_kind_handlers, |
- arraysize(kElementsKind)); |
- |
- Bind(&if_smiorobjects); |
- { |
- Variable search_num(this, MachineRepresentation::kFloat64); |
- Label ident_loop(this, &index_var), heap_num_loop(this, &search_num), |
- string_loop(this, &index_var), not_smi(this), not_heap_num(this); |
- |
- GotoIfNot(TaggedIsSmi(search_element), ¬_smi); |
- search_num.Bind(SmiToFloat64(search_element)); |
- Goto(&heap_num_loop); |
- |
- Bind(¬_smi); |
- Node* map = LoadMap(search_element); |
- GotoIfNot(IsHeapNumberMap(map), ¬_heap_num); |
- search_num.Bind(LoadHeapNumberValue(search_element)); |
- Goto(&heap_num_loop); |
- |
- Bind(¬_heap_num); |
- Node* search_type = LoadMapInstanceType(map); |
- GotoIf(IsStringInstanceType(search_type), &string_loop); |
- Goto(&ident_loop); |
- |
- Bind(&ident_loop); |
- { |
- GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), |
- &return_not_found); |
- Node* element_k = LoadFixedArrayElement(elements, index_var.value()); |
- GotoIf(WordEqual(element_k, search_element), &return_found); |
- |
- index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); |
- Goto(&ident_loop); |
- } |
- |
- Bind(&heap_num_loop); |
- { |
- Label not_nan_loop(this, &index_var); |
- BranchIfFloat64IsNaN(search_num.value(), &return_not_found, |
- ¬_nan_loop); |
- |
- Bind(¬_nan_loop); |
- { |
- Label continue_loop(this), not_smi(this); |
- GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), |
- &return_not_found); |
- Node* element_k = LoadFixedArrayElement(elements, index_var.value()); |
- GotoIfNot(TaggedIsSmi(element_k), ¬_smi); |
- Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)), |
- &return_found, &continue_loop); |
- |
- Bind(¬_smi); |
- GotoIfNot(IsHeapNumber(element_k), &continue_loop); |
- Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)), |
- &return_found, &continue_loop); |
- |
- Bind(&continue_loop); |
- index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); |
- Goto(¬_nan_loop); |
- } |
- } |
- |
- Bind(&string_loop); |
- { |
- Label continue_loop(this); |
- GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), |
- &return_not_found); |
- Node* element_k = LoadFixedArrayElement(elements, index_var.value()); |
- GotoIf(TaggedIsSmi(element_k), &continue_loop); |
- GotoIfNot(IsString(element_k), &continue_loop); |
- |
- // TODO(bmeurer): Consider inlining the StringEqual logic here. |
- Callable callable = CodeFactory::StringEqual(isolate()); |
- Node* result = CallStub(callable, context, search_element, element_k); |
- Branch(WordEqual(BooleanConstant(true), result), &return_found, |
- &continue_loop); |
- |
- Bind(&continue_loop); |
- index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); |
- Goto(&string_loop); |
- } |
- } |
- |
- Bind(&if_packed_doubles); |
- { |
- Label not_nan_loop(this, &index_var), search_notnan(this); |
- Variable search_num(this, MachineRepresentation::kFloat64); |
- |
- GotoIfNot(TaggedIsSmi(search_element), &search_notnan); |
- search_num.Bind(SmiToFloat64(search_element)); |
- Goto(¬_nan_loop); |
- |
- Bind(&search_notnan); |
- GotoIfNot(IsHeapNumber(search_element), &return_not_found); |
- |
- search_num.Bind(LoadHeapNumberValue(search_element)); |
- |
- BranchIfFloat64IsNaN(search_num.value(), &return_not_found, ¬_nan_loop); |
- |
- // Search for HeapNumber |
- Bind(¬_nan_loop); |
- { |
- GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), |
- &return_not_found); |
- Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(), |
- MachineType::Float64()); |
- GotoIf(Float64Equal(element_k, search_num.value()), &return_found); |
- |
- index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); |
- Goto(¬_nan_loop); |
- } |
- } |
- |
- Bind(&if_holey_doubles); |
- { |
- Label not_nan_loop(this, &index_var), search_notnan(this); |
- Variable search_num(this, MachineRepresentation::kFloat64); |
- |
- GotoIfNot(TaggedIsSmi(search_element), &search_notnan); |
- search_num.Bind(SmiToFloat64(search_element)); |
- Goto(¬_nan_loop); |
- |
- Bind(&search_notnan); |
- GotoIfNot(IsHeapNumber(search_element), &return_not_found); |
- |
- search_num.Bind(LoadHeapNumberValue(search_element)); |
- |
- BranchIfFloat64IsNaN(search_num.value(), &return_not_found, ¬_nan_loop); |
- |
- // Search for HeapNumber |
- Bind(¬_nan_loop); |
- { |
- Label continue_loop(this); |
- GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), |
- &return_not_found); |
- |
- // Load double value or continue if it contains a double hole. |
- Node* element_k = LoadFixedDoubleArrayElement( |
- elements, index_var.value(), MachineType::Float64(), 0, |
- INTPTR_PARAMETERS, &continue_loop); |
- |
- Branch(Float64Equal(element_k, search_num.value()), &return_found, |
- &continue_loop); |
- Bind(&continue_loop); |
- index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); |
- Goto(¬_nan_loop); |
- } |
- } |
- |
- Bind(&return_found); |
- Return(SmiTag(index_var.value())); |
- |
- Bind(&return_not_found); |
- Return(NumberConstant(-1)); |
- |
- Bind(&call_runtime); |
- Return(CallRuntime(Runtime::kArrayIndexOf, context, array, search_element, |
- start_from)); |
-} |
- |
-class ArrayPrototypeIterationAssembler : public CodeStubAssembler { |
- public: |
- explicit ArrayPrototypeIterationAssembler(compiler::CodeAssemblerState* state) |
- : CodeStubAssembler(state) {} |
- |
- protected: |
- void Generate_ArrayPrototypeIterationMethod(IterationKind iteration_kind) { |
- Node* receiver = Parameter(0); |
- Node* context = Parameter(3); |
- |
- Variable var_array(this, MachineRepresentation::kTagged); |
- Variable var_map(this, MachineRepresentation::kTagged); |
- Variable var_type(this, MachineRepresentation::kWord32); |
- |
- Label if_isnotobject(this, Label::kDeferred); |
- Label create_array_iterator(this); |
- |
- GotoIf(TaggedIsSmi(receiver), &if_isnotobject); |
- var_array.Bind(receiver); |
- var_map.Bind(LoadMap(receiver)); |
- var_type.Bind(LoadMapInstanceType(var_map.value())); |
- Branch(IsJSReceiverInstanceType(var_type.value()), &create_array_iterator, |
- &if_isnotobject); |
- |
- Bind(&if_isnotobject); |
- { |
- Callable callable = CodeFactory::ToObject(isolate()); |
- Node* result = CallStub(callable, context, receiver); |
- var_array.Bind(result); |
- var_map.Bind(LoadMap(result)); |
- var_type.Bind(LoadMapInstanceType(var_map.value())); |
- Goto(&create_array_iterator); |
- } |
- |
- Bind(&create_array_iterator); |
- Return(CreateArrayIterator(var_array.value(), var_map.value(), |
- var_type.value(), context, iteration_kind)); |
- } |
-}; |
- |
-TF_BUILTIN(ArrayPrototypeValues, ArrayPrototypeIterationAssembler) { |
- Generate_ArrayPrototypeIterationMethod(IterationKind::kValues); |
-} |
- |
-TF_BUILTIN(ArrayPrototypeEntries, ArrayPrototypeIterationAssembler) { |
- Generate_ArrayPrototypeIterationMethod(IterationKind::kEntries); |
-} |
- |
-TF_BUILTIN(ArrayPrototypeKeys, ArrayPrototypeIterationAssembler) { |
- Generate_ArrayPrototypeIterationMethod(IterationKind::kKeys); |
-} |
- |
-TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) { |
- Handle<String> operation = factory()->NewStringFromAsciiChecked( |
- "Array Iterator.prototype.next", TENURED); |
- |
- Node* iterator = Parameter(0); |
- Node* context = Parameter(3); |
- |
- Variable var_value(this, MachineRepresentation::kTagged); |
- Variable var_done(this, MachineRepresentation::kTagged); |
- |
- // Required, or else `throw_bad_receiver` fails a DCHECK due to these |
- // variables not being bound along all paths, despite not being used. |
- var_done.Bind(TrueConstant()); |
- var_value.Bind(UndefinedConstant()); |
- |
- Label throw_bad_receiver(this, Label::kDeferred); |
- Label set_done(this); |
- Label allocate_key_result(this); |
- Label allocate_entry_if_needed(this); |
- Label allocate_iterator_result(this); |
- Label generic_values(this); |
- |
- // If O does not have all of the internal slots of an Array Iterator Instance |
- // (22.1.5.3), throw a TypeError exception |
- GotoIf(TaggedIsSmi(iterator), &throw_bad_receiver); |
- Node* instance_type = LoadInstanceType(iterator); |
- GotoIf( |
- Uint32LessThan( |
- Int32Constant(LAST_ARRAY_ITERATOR_TYPE - FIRST_ARRAY_ITERATOR_TYPE), |
- Int32Sub(instance_type, Int32Constant(FIRST_ARRAY_ITERATOR_TYPE))), |
- &throw_bad_receiver); |
- |
- // Let a be O.[[IteratedObject]]. |
- Node* array = |
- LoadObjectField(iterator, JSArrayIterator::kIteratedObjectOffset); |
- |
- // Let index be O.[[ArrayIteratorNextIndex]]. |
- Node* index = LoadObjectField(iterator, JSArrayIterator::kNextIndexOffset); |
- Node* orig_map = |
- LoadObjectField(iterator, JSArrayIterator::kIteratedObjectMapOffset); |
- Node* array_map = LoadMap(array); |
- |
- Label if_isfastarray(this), if_isnotfastarray(this), |
- if_isdetached(this, Label::kDeferred); |
- |
- Branch(WordEqual(orig_map, array_map), &if_isfastarray, &if_isnotfastarray); |
- |
- Bind(&if_isfastarray); |
- { |
- CSA_ASSERT(this, Word32Equal(LoadMapInstanceType(array_map), |
- Int32Constant(JS_ARRAY_TYPE))); |
- |
- Node* length = LoadObjectField(array, JSArray::kLengthOffset); |
- |
- CSA_ASSERT(this, TaggedIsSmi(length)); |
- CSA_ASSERT(this, TaggedIsSmi(index)); |
- |
- GotoIfNot(SmiBelow(index, length), &set_done); |
- |
- Node* one = SmiConstant(Smi::FromInt(1)); |
- StoreObjectFieldNoWriteBarrier(iterator, JSArrayIterator::kNextIndexOffset, |
- SmiAdd(index, one)); |
- |
- var_done.Bind(FalseConstant()); |
- Node* elements = LoadElements(array); |
- |
- static int32_t kInstanceType[] = { |
- JS_FAST_ARRAY_KEY_ITERATOR_TYPE, |
- JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE, |
- JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE, |
- JS_FAST_ARRAY_VALUE_ITERATOR_TYPE, |
- JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE, |
- JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE, |
- JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE, |
- }; |
- |
- Label packed_object_values(this), holey_object_values(this), |
- packed_double_values(this), holey_double_values(this); |
- Label* kInstanceTypeHandlers[] = { |
- &allocate_key_result, &packed_object_values, &holey_object_values, |
- &packed_object_values, &holey_object_values, &packed_double_values, |
- &holey_double_values, &packed_object_values, &holey_object_values, |
- &packed_object_values, &holey_object_values, &packed_double_values, |
- &holey_double_values}; |
- |
- Switch(instance_type, &throw_bad_receiver, kInstanceType, |
- kInstanceTypeHandlers, arraysize(kInstanceType)); |
- |
- Bind(&packed_object_values); |
- { |
- var_value.Bind(LoadFixedArrayElement(elements, index, 0, SMI_PARAMETERS)); |
- Goto(&allocate_entry_if_needed); |
- } |
- |
- Bind(&packed_double_values); |
- { |
- Node* value = LoadFixedDoubleArrayElement( |
- elements, index, MachineType::Float64(), 0, SMI_PARAMETERS); |
- var_value.Bind(AllocateHeapNumberWithValue(value)); |
- Goto(&allocate_entry_if_needed); |
- } |
- |
- Bind(&holey_object_values); |
- { |
- // Check the array_protector cell, and take the slow path if it's invalid. |
- Node* invalid = SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid)); |
- Node* cell = LoadRoot(Heap::kArrayProtectorRootIndex); |
- Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); |
- GotoIf(WordEqual(cell_value, invalid), &generic_values); |
- |
- var_value.Bind(UndefinedConstant()); |
- Node* value = LoadFixedArrayElement(elements, index, 0, SMI_PARAMETERS); |
- GotoIf(WordEqual(value, TheHoleConstant()), &allocate_entry_if_needed); |
- var_value.Bind(value); |
- Goto(&allocate_entry_if_needed); |
- } |
- |
- Bind(&holey_double_values); |
- { |
- // Check the array_protector cell, and take the slow path if it's invalid. |
- Node* invalid = SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid)); |
- Node* cell = LoadRoot(Heap::kArrayProtectorRootIndex); |
- Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); |
- GotoIf(WordEqual(cell_value, invalid), &generic_values); |
- |
- var_value.Bind(UndefinedConstant()); |
- Node* value = LoadFixedDoubleArrayElement( |
- elements, index, MachineType::Float64(), 0, SMI_PARAMETERS, |
- &allocate_entry_if_needed); |
- var_value.Bind(AllocateHeapNumberWithValue(value)); |
- Goto(&allocate_entry_if_needed); |
- } |
- } |
- |
- Bind(&if_isnotfastarray); |
- { |
- Label if_istypedarray(this), if_isgeneric(this); |
- |
- // If a is undefined, return CreateIterResultObject(undefined, true) |
- GotoIf(WordEqual(array, UndefinedConstant()), &allocate_iterator_result); |
- |
- Node* array_type = LoadInstanceType(array); |
- Branch(Word32Equal(array_type, Int32Constant(JS_TYPED_ARRAY_TYPE)), |
- &if_istypedarray, &if_isgeneric); |
- |
- Bind(&if_isgeneric); |
- { |
- Label if_wasfastarray(this); |
- |
- Node* length = nullptr; |
- { |
- Variable var_length(this, MachineRepresentation::kTagged); |
- Label if_isarray(this), if_isnotarray(this), done(this); |
- Branch(Word32Equal(array_type, Int32Constant(JS_ARRAY_TYPE)), |
- &if_isarray, &if_isnotarray); |
- |
- Bind(&if_isarray); |
- { |
- var_length.Bind(LoadObjectField(array, JSArray::kLengthOffset)); |
- |
- // Invalidate protector cell if needed |
- Branch(WordNotEqual(orig_map, UndefinedConstant()), &if_wasfastarray, |
- &done); |
- |
- Bind(&if_wasfastarray); |
- { |
- Label if_invalid(this, Label::kDeferred); |
- // A fast array iterator transitioned to a slow iterator during |
- // iteration. Invalidate fast_array_iteration_prtoector cell to |
- // prevent potential deopt loops. |
- StoreObjectFieldNoWriteBarrier( |
- iterator, JSArrayIterator::kIteratedObjectMapOffset, |
- UndefinedConstant()); |
- GotoIf(Uint32LessThanOrEqual( |
- instance_type, |
- Int32Constant(JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)), |
- &done); |
- |
- Node* invalid = |
- SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid)); |
- Node* cell = LoadRoot(Heap::kFastArrayIterationProtectorRootIndex); |
- StoreObjectFieldNoWriteBarrier(cell, Cell::kValueOffset, invalid); |
- Goto(&done); |
- } |
- } |
- |
- Bind(&if_isnotarray); |
- { |
- Node* length = |
- GetProperty(context, array, factory()->length_string()); |
- Callable to_length = CodeFactory::ToLength(isolate()); |
- var_length.Bind(CallStub(to_length, context, length)); |
- Goto(&done); |
- } |
- |
- Bind(&done); |
- length = var_length.value(); |
- } |
- |
- GotoUnlessNumberLessThan(index, length, &set_done); |
- |
- StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset, |
- NumberInc(index)); |
- var_done.Bind(FalseConstant()); |
- |
- Branch( |
- Uint32LessThanOrEqual( |
- instance_type, Int32Constant(JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)), |
- &allocate_key_result, &generic_values); |
- |
- Bind(&generic_values); |
- { |
- var_value.Bind(GetProperty(context, array, index)); |
- Goto(&allocate_entry_if_needed); |
- } |
- } |
- |
- Bind(&if_istypedarray); |
- { |
- Node* buffer = LoadObjectField(array, JSTypedArray::kBufferOffset); |
- GotoIf(IsDetachedBuffer(buffer), &if_isdetached); |
- |
- Node* length = LoadObjectField(array, JSTypedArray::kLengthOffset); |
- |
- CSA_ASSERT(this, TaggedIsSmi(length)); |
- CSA_ASSERT(this, TaggedIsSmi(index)); |
- |
- GotoIfNot(SmiBelow(index, length), &set_done); |
- |
- Node* one = SmiConstant(1); |
- StoreObjectFieldNoWriteBarrier( |
- iterator, JSArrayIterator::kNextIndexOffset, SmiAdd(index, one)); |
- var_done.Bind(FalseConstant()); |
- |
- Node* elements = LoadElements(array); |
- Node* base_ptr = |
- LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); |
- Node* external_ptr = |
- LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, |
- MachineType::Pointer()); |
- Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr); |
- |
- static int32_t kInstanceType[] = { |
- JS_TYPED_ARRAY_KEY_ITERATOR_TYPE, |
- JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE, |
- JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE, |
- JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE, |
- JS_INT8_ARRAY_VALUE_ITERATOR_TYPE, |
- JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE, |
- JS_INT16_ARRAY_VALUE_ITERATOR_TYPE, |
- JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE, |
- JS_INT32_ARRAY_VALUE_ITERATOR_TYPE, |
- JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE, |
- JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE, |
- }; |
- |
- Label uint8_values(this), int8_values(this), uint16_values(this), |
- int16_values(this), uint32_values(this), int32_values(this), |
- float32_values(this), float64_values(this); |
- Label* kInstanceTypeHandlers[] = { |
- &allocate_key_result, &uint8_values, &uint8_values, |
- &int8_values, &uint16_values, &int16_values, |
- &uint32_values, &int32_values, &float32_values, |
- &float64_values, &uint8_values, &uint8_values, |
- &int8_values, &uint16_values, &int16_values, |
- &uint32_values, &int32_values, &float32_values, |
- &float64_values, |
- }; |
- |
- var_done.Bind(FalseConstant()); |
- Switch(instance_type, &throw_bad_receiver, kInstanceType, |
- kInstanceTypeHandlers, arraysize(kInstanceType)); |
- |
- Bind(&uint8_values); |
- { |
- Node* value_uint8 = LoadFixedTypedArrayElement( |
- data_ptr, index, UINT8_ELEMENTS, SMI_PARAMETERS); |
- var_value.Bind(SmiFromWord32(value_uint8)); |
- Goto(&allocate_entry_if_needed); |
- } |
- Bind(&int8_values); |
- { |
- Node* value_int8 = LoadFixedTypedArrayElement( |
- data_ptr, index, INT8_ELEMENTS, SMI_PARAMETERS); |
- var_value.Bind(SmiFromWord32(value_int8)); |
- Goto(&allocate_entry_if_needed); |
- } |
- Bind(&uint16_values); |
- { |
- Node* value_uint16 = LoadFixedTypedArrayElement( |
- data_ptr, index, UINT16_ELEMENTS, SMI_PARAMETERS); |
- var_value.Bind(SmiFromWord32(value_uint16)); |
- Goto(&allocate_entry_if_needed); |
- } |
- Bind(&int16_values); |
- { |
- Node* value_int16 = LoadFixedTypedArrayElement( |
- data_ptr, index, INT16_ELEMENTS, SMI_PARAMETERS); |
- var_value.Bind(SmiFromWord32(value_int16)); |
- Goto(&allocate_entry_if_needed); |
- } |
- Bind(&uint32_values); |
- { |
- Node* value_uint32 = LoadFixedTypedArrayElement( |
- data_ptr, index, UINT32_ELEMENTS, SMI_PARAMETERS); |
- var_value.Bind(ChangeUint32ToTagged(value_uint32)); |
- Goto(&allocate_entry_if_needed); |
- } |
- Bind(&int32_values); |
- { |
- Node* value_int32 = LoadFixedTypedArrayElement( |
- data_ptr, index, INT32_ELEMENTS, SMI_PARAMETERS); |
- var_value.Bind(ChangeInt32ToTagged(value_int32)); |
- Goto(&allocate_entry_if_needed); |
- } |
- Bind(&float32_values); |
- { |
- Node* value_float32 = LoadFixedTypedArrayElement( |
- data_ptr, index, FLOAT32_ELEMENTS, SMI_PARAMETERS); |
- var_value.Bind( |
- AllocateHeapNumberWithValue(ChangeFloat32ToFloat64(value_float32))); |
- Goto(&allocate_entry_if_needed); |
- } |
- Bind(&float64_values); |
- { |
- Node* value_float64 = LoadFixedTypedArrayElement( |
- data_ptr, index, FLOAT64_ELEMENTS, SMI_PARAMETERS); |
- var_value.Bind(AllocateHeapNumberWithValue(value_float64)); |
- Goto(&allocate_entry_if_needed); |
- } |
- } |
- } |
- |
- Bind(&set_done); |
- { |
- StoreObjectFieldNoWriteBarrier( |
- iterator, JSArrayIterator::kIteratedObjectOffset, UndefinedConstant()); |
- Goto(&allocate_iterator_result); |
- } |
- |
- Bind(&allocate_key_result); |
- { |
- var_value.Bind(index); |
- var_done.Bind(FalseConstant()); |
- Goto(&allocate_iterator_result); |
- } |
- |
- Bind(&allocate_entry_if_needed); |
- { |
- GotoIf(Int32GreaterThan(instance_type, |
- Int32Constant(LAST_ARRAY_KEY_VALUE_ITERATOR_TYPE)), |
- &allocate_iterator_result); |
- |
- Node* elements = AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); |
- StoreFixedArrayElement(elements, 0, index, SKIP_WRITE_BARRIER); |
- StoreFixedArrayElement(elements, 1, var_value.value(), SKIP_WRITE_BARRIER); |
- |
- Node* entry = Allocate(JSArray::kSize); |
- Node* map = LoadContextElement(LoadNativeContext(context), |
- Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX); |
- |
- StoreMapNoWriteBarrier(entry, map); |
- StoreObjectFieldRoot(entry, JSArray::kPropertiesOffset, |
- Heap::kEmptyFixedArrayRootIndex); |
- StoreObjectFieldNoWriteBarrier(entry, JSArray::kElementsOffset, elements); |
- StoreObjectFieldNoWriteBarrier(entry, JSArray::kLengthOffset, |
- SmiConstant(Smi::FromInt(2))); |
- |
- var_value.Bind(entry); |
- Goto(&allocate_iterator_result); |
- } |
- |
- Bind(&allocate_iterator_result); |
- { |
- Node* result = Allocate(JSIteratorResult::kSize); |
- Node* map = LoadContextElement(LoadNativeContext(context), |
- Context::ITERATOR_RESULT_MAP_INDEX); |
- StoreMapNoWriteBarrier(result, map); |
- StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset, |
- Heap::kEmptyFixedArrayRootIndex); |
- StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset, |
- Heap::kEmptyFixedArrayRootIndex); |
- StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, |
- var_value.value()); |
- StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset, |
- var_done.value()); |
- Return(result); |
- } |
- |
- Bind(&throw_bad_receiver); |
- { |
- // The {receiver} is not a valid JSArrayIterator. |
- CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context, |
- HeapConstant(operation), iterator); |
- Unreachable(); |
- } |
- |
- Bind(&if_isdetached); |
- { |
- Node* message = SmiConstant(MessageTemplate::kDetachedOperation); |
- CallRuntime(Runtime::kThrowTypeError, context, message, |
- HeapConstant(operation)); |
- Unreachable(); |
- } |
-} |
- |
} // namespace internal |
} // namespace v8 |