OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins/builtins.h" | 5 #include "src/builtins/builtins.h" |
6 #include "src/builtins/builtins-utils.h" | 6 #include "src/builtins/builtins-utils.h" |
7 | 7 |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/code-stub-assembler.h" | 9 #include "src/code-stub-assembler.h" |
10 #include "src/contexts.h" | 10 #include "src/contexts.h" |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 | 181 |
182 if (JSArray::HasReadOnlyLength(array)) { | 182 if (JSArray::HasReadOnlyLength(array)) { |
183 return CallJsIntrinsic(isolate, isolate->array_push(), args); | 183 return CallJsIntrinsic(isolate, isolate->array_push(), args); |
184 } | 184 } |
185 | 185 |
186 ElementsAccessor* accessor = array->GetElementsAccessor(); | 186 ElementsAccessor* accessor = array->GetElementsAccessor(); |
187 int new_length = accessor->Push(array, &args, to_add); | 187 int new_length = accessor->Push(array, &args, to_add); |
188 return Smi::FromInt(new_length); | 188 return Smi::FromInt(new_length); |
189 } | 189 } |
190 | 190 |
191 TF_BUILTIN(FastArrayPush, CodeStubAssembler) { | |
192 Variable arg_index(this, MachineType::PointerRepresentation()); | |
193 Label default_label(this, &arg_index); | |
194 Label smi_transition(this); | |
195 Label object_push_pre(this); | |
196 Label object_push(this, &arg_index); | |
197 Label double_push(this, &arg_index); | |
198 Label double_transition(this); | |
199 Label runtime(this, Label::kDeferred); | |
200 | |
201 Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount); | |
202 Node* context = Parameter(BuiltinDescriptor::kContext); | |
203 Node* new_target = Parameter(BuiltinDescriptor::kNewTarget); | |
204 | |
205 CodeStubArguments args(this, ChangeInt32ToIntPtr(argc)); | |
206 Node* receiver = args.GetReceiver(); | |
207 Node* kind = nullptr; | |
208 | |
209 Label fast(this); | |
210 BranchIfFastJSArray(receiver, context, FastJSArrayAccessMode::ANY_ACCESS, | |
211 &fast, &runtime); | |
212 | |
213 Bind(&fast); | |
214 { | |
215 // Disallow pushing onto prototypes. It might be the JSArray prototype. | |
216 // Disallow pushing onto non-extensible objects. | |
217 Comment("Disallow pushing onto prototypes"); | |
218 Node* map = LoadMap(receiver); | |
219 Node* bit_field2 = LoadMapBitField2(map); | |
220 int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) | | |
221 (1 << Map::kIsExtensible); | |
222 Node* test = Word32And(bit_field2, Int32Constant(mask)); | |
223 GotoIf(Word32NotEqual(test, Int32Constant(1 << Map::kIsExtensible)), | |
224 &runtime); | |
225 | |
226 // Disallow pushing onto arrays in dictionary named property mode. We need | |
227 // to figure out whether the length property is still writable. | |
228 Comment("Disallow pushing onto arrays in dictionary named property mode"); | |
229 GotoIf(IsDictionaryMap(map), &runtime); | |
230 | |
231 // Check whether the length property is writable. The length property is the | |
232 // only default named property on arrays. It's nonconfigurable, hence is | |
233 // guaranteed to stay the first property. | |
234 Node* descriptors = LoadMapDescriptors(map); | |
235 Node* details = | |
236 LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0)); | |
237 GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask), | |
238 &runtime); | |
239 | |
240 arg_index.Bind(IntPtrConstant(0)); | |
241 kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); | |
242 | |
243 GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)), | |
244 &object_push_pre); | |
245 | |
246 Node* new_length = BuildAppendJSArray(FAST_SMI_ELEMENTS, context, receiver, | |
247 args, arg_index, &smi_transition); | |
248 args.PopAndReturn(new_length); | |
249 } | |
250 | |
251 // If the argument is not a smi, then use a heavyweight SetProperty to | |
252 // transition the array for only the single next element. If the argument is | |
253 // a smi, the failure is due to some other reason and we should fall back on | |
254 // the most generic implementation for the rest of the array. | |
255 Bind(&smi_transition); | |
256 { | |
257 Node* arg = args.AtIndex(arg_index.value()); | |
258 GotoIf(TaggedIsSmi(arg), &default_label); | |
259 Node* length = LoadJSArrayLength(receiver); | |
260 // TODO(danno): Use the KeyedStoreGeneric stub here when possible, | |
261 // calling into the runtime to do the elements transition is overkill. | |
262 CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, | |
263 SmiConstant(STRICT)); | |
264 Increment(arg_index); | |
265 // The runtime SetProperty call could have converted the array to dictionary | |
266 // mode, which must be detected to abort the fast-path. | |
267 Node* map = LoadMap(receiver); | |
268 Node* bit_field2 = LoadMapBitField2(map); | |
269 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); | |
270 GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)), | |
271 &default_label); | |
272 | |
273 GotoIfNotNumber(arg, &object_push); | |
274 Goto(&double_push); | |
275 } | |
276 | |
277 Bind(&object_push_pre); | |
278 { | |
279 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | |
280 &double_push, &object_push); | |
281 } | |
282 | |
283 Bind(&object_push); | |
284 { | |
285 Node* new_length = BuildAppendJSArray(FAST_ELEMENTS, context, receiver, | |
286 args, arg_index, &default_label); | |
287 args.PopAndReturn(new_length); | |
288 } | |
289 | |
290 Bind(&double_push); | |
291 { | |
292 Node* new_length = | |
293 BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver, args, | |
294 arg_index, &double_transition); | |
295 args.PopAndReturn(new_length); | |
296 } | |
297 | |
298 // If the argument is not a double, then use a heavyweight SetProperty to | |
299 // transition the array for only the single next element. If the argument is | |
300 // a double, the failure is due to some other reason and we should fall back | |
301 // on the most generic implementation for the rest of the array. | |
302 Bind(&double_transition); | |
303 { | |
304 Node* arg = args.AtIndex(arg_index.value()); | |
305 GotoIfNumber(arg, &default_label); | |
306 Node* length = LoadJSArrayLength(receiver); | |
307 // TODO(danno): Use the KeyedStoreGeneric stub here when possible, | |
308 // calling into the runtime to do the elements transition is overkill. | |
309 CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, | |
310 SmiConstant(STRICT)); | |
311 Increment(arg_index); | |
312 // The runtime SetProperty call could have converted the array to dictionary | |
313 // mode, which must be detected to abort the fast-path. | |
314 Node* map = LoadMap(receiver); | |
315 Node* bit_field2 = LoadMapBitField2(map); | |
316 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); | |
317 GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)), | |
318 &default_label); | |
319 Goto(&object_push); | |
320 } | |
321 | |
322 // Fallback that stores un-processed arguments using the full, heavyweight | |
323 // SetProperty machinery. | |
324 Bind(&default_label); | |
325 { | |
326 args.ForEach( | |
327 [this, receiver, context](Node* arg) { | |
328 Node* length = LoadJSArrayLength(receiver); | |
329 CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, | |
330 SmiConstant(STRICT)); | |
331 }, | |
332 arg_index.value()); | |
333 args.PopAndReturn(LoadJSArrayLength(receiver)); | |
334 } | |
335 | |
336 Bind(&runtime); | |
337 { | |
338 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, | |
339 MachineType::TaggedPointer()); | |
340 TailCallStub(CodeFactory::ArrayPush(isolate()), context, target, new_target, | |
341 argc); | |
342 } | |
343 } | |
344 | |
345 BUILTIN(ArrayPop) { | 191 BUILTIN(ArrayPop) { |
346 HandleScope scope(isolate); | 192 HandleScope scope(isolate); |
347 Handle<Object> receiver = args.receiver(); | 193 Handle<Object> receiver = args.receiver(); |
348 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) { | 194 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) { |
349 return CallJsIntrinsic(isolate, isolate->array_pop(), args); | 195 return CallJsIntrinsic(isolate, isolate->array_pop(), args); |
350 } | 196 } |
351 | 197 |
352 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 198 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
353 | 199 |
354 uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value()); | 200 uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value()); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
408 | 254 |
409 if (JSArray::HasReadOnlyLength(array)) { | 255 if (JSArray::HasReadOnlyLength(array)) { |
410 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); | 256 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); |
411 } | 257 } |
412 | 258 |
413 ElementsAccessor* accessor = array->GetElementsAccessor(); | 259 ElementsAccessor* accessor = array->GetElementsAccessor(); |
414 int new_length = accessor->Unshift(array, &args, to_add); | 260 int new_length = accessor->Unshift(array, &args, to_add); |
415 return Smi::FromInt(new_length); | 261 return Smi::FromInt(new_length); |
416 } | 262 } |
417 | 263 |
418 class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { | |
419 public: | |
420 explicit ArrayBuiltinCodeStubAssembler(compiler::CodeAssemblerState* state) | |
421 : CodeStubAssembler(state) {} | |
422 | |
423 typedef std::function<Node*(Node* o, Node* len)> BuiltinResultGenerator; | |
424 typedef std::function<void(Node* a, Node* pK, Node* value)> | |
425 CallResultProcessor; | |
426 | |
427 void GenerateArrayIteratingBuiltinBody( | |
428 const char* name, Node* receiver, Node* callbackfn, Node* this_arg, | |
429 Node* context, const BuiltinResultGenerator& generator, | |
430 const CallResultProcessor& processor) { | |
431 Variable k(this, MachineRepresentation::kTagged, SmiConstant(0)); | |
432 Label non_array(this), slow(this, &k), array_changes(this, &k); | |
433 | |
434 // TODO(danno): Seriously? Do we really need to throw the exact error | |
435 // message on null and undefined so that the webkit tests pass? | |
436 Label throw_null_undefined_exception(this, Label::kDeferred); | |
437 GotoIf(WordEqual(receiver, NullConstant()), | |
438 &throw_null_undefined_exception); | |
439 GotoIf(WordEqual(receiver, UndefinedConstant()), | |
440 &throw_null_undefined_exception); | |
441 | |
442 // By the book: taken directly from the ECMAScript 2015 specification | |
443 | |
444 // 1. Let O be ToObject(this value). | |
445 // 2. ReturnIfAbrupt(O) | |
446 Node* o = CallStub(CodeFactory::ToObject(isolate()), context, receiver); | |
447 | |
448 // 3. Let len be ToLength(Get(O, "length")). | |
449 // 4. ReturnIfAbrupt(len). | |
450 Variable merged_length(this, MachineRepresentation::kTagged); | |
451 Label has_length(this, &merged_length), not_js_array(this); | |
452 GotoIf(DoesntHaveInstanceType(o, JS_ARRAY_TYPE), ¬_js_array); | |
453 merged_length.Bind(LoadJSArrayLength(o)); | |
454 Goto(&has_length); | |
455 Bind(¬_js_array); | |
456 Node* len_property = | |
457 GetProperty(context, o, isolate()->factory()->length_string()); | |
458 merged_length.Bind( | |
459 CallStub(CodeFactory::ToLength(isolate()), context, len_property)); | |
460 Goto(&has_length); | |
461 Bind(&has_length); | |
462 Node* len = merged_length.value(); | |
463 | |
464 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. | |
465 Label type_exception(this, Label::kDeferred); | |
466 Label done(this); | |
467 GotoIf(TaggedIsSmi(callbackfn), &type_exception); | |
468 Branch(IsCallableMap(LoadMap(callbackfn)), &done, &type_exception); | |
469 | |
470 Bind(&throw_null_undefined_exception); | |
471 { | |
472 CallRuntime( | |
473 Runtime::kThrowTypeError, context, | |
474 SmiConstant(MessageTemplate::kCalledOnNullOrUndefined), | |
475 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked(name))); | |
476 Unreachable(); | |
477 } | |
478 | |
479 Bind(&type_exception); | |
480 { | |
481 CallRuntime(Runtime::kThrowTypeError, context, | |
482 SmiConstant(MessageTemplate::kCalledNonCallable), callbackfn); | |
483 Unreachable(); | |
484 } | |
485 | |
486 Bind(&done); | |
487 | |
488 Node* a = generator(o, len); | |
489 | |
490 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. | |
491 // [Already done by the arguments adapter] | |
492 | |
493 HandleFastElements(context, this_arg, o, len, callbackfn, processor, a, k, | |
494 &slow); | |
495 | |
496 // 7. Let k be 0. | |
497 // Already done above in initialization of the Variable k | |
498 | |
499 Bind(&slow); | |
500 { | |
501 // 8. Repeat, while k < len | |
502 Label loop(this, &k); | |
503 Label after_loop(this); | |
504 Goto(&loop); | |
505 Bind(&loop); | |
506 { | |
507 GotoUnlessNumberLessThan(k.value(), len, &after_loop); | |
508 | |
509 Label done_element(this); | |
510 // a. Let Pk be ToString(k). | |
511 Node* p_k = ToString(context, k.value()); | |
512 | |
513 // b. Let kPresent be HasProperty(O, Pk). | |
514 // c. ReturnIfAbrupt(kPresent). | |
515 Node* k_present = | |
516 CallStub(CodeFactory::HasProperty(isolate()), context, p_k, o); | |
517 | |
518 // d. If kPresent is true, then | |
519 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); | |
520 | |
521 // i. Let kValue be Get(O, Pk). | |
522 // ii. ReturnIfAbrupt(kValue). | |
523 Node* k_value = GetProperty(context, o, k.value()); | |
524 | |
525 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). | |
526 // iv. ReturnIfAbrupt(funcResult). | |
527 Node* result = CallJS(CodeFactory::Call(isolate()), context, callbackfn, | |
528 this_arg, k_value, k.value(), o); | |
529 | |
530 processor(a, p_k, result); | |
531 Goto(&done_element); | |
532 Bind(&done_element); | |
533 | |
534 // e. Increase k by 1. | |
535 k.Bind(NumberInc(k.value())); | |
536 Goto(&loop); | |
537 } | |
538 Bind(&after_loop); | |
539 Return(a); | |
540 } | |
541 } | |
542 | |
543 private: | |
544 Node* VisitAllFastElementsOneKind(Node* context, ElementsKind kind, | |
545 Node* this_arg, Node* o, Node* len, | |
546 Node* callbackfn, | |
547 const CallResultProcessor& processor, | |
548 Node* a, Label* array_changed, | |
549 ParameterMode mode) { | |
550 Comment("begin VisitAllFastElementsOneKind"); | |
551 Variable original_map(this, MachineRepresentation::kTagged); | |
552 original_map.Bind(LoadMap(o)); | |
553 VariableList list({&original_map}, zone()); | |
554 Node* last_index = nullptr; | |
555 BuildFastLoop( | |
556 list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode), | |
557 [=, &original_map, &last_index](Node* index) { | |
558 last_index = index; | |
559 Label one_element_done(this), hole_element(this); | |
560 | |
561 // Check if o's map has changed during the callback. If so, we have to | |
562 // fall back to the slower spec implementation for the rest of the | |
563 // iteration. | |
564 Node* o_map = LoadMap(o); | |
565 GotoIf(WordNotEqual(o_map, original_map.value()), array_changed); | |
566 | |
567 // Check if o's length has changed during the callback and if the | |
568 // index is now out of range of the new length. | |
569 Node* tagged_index = ParameterToTagged(index, mode); | |
570 GotoIf(SmiGreaterThanOrEqual(tagged_index, LoadJSArrayLength(o)), | |
571 array_changed); | |
572 | |
573 // Re-load the elements array. If may have been resized. | |
574 Node* elements = LoadElements(o); | |
575 | |
576 // Fast case: load the element directly from the elements FixedArray | |
577 // and call the callback if the element is not the hole. | |
578 DCHECK(kind == FAST_ELEMENTS || kind == FAST_DOUBLE_ELEMENTS); | |
579 int base_size = kind == FAST_ELEMENTS | |
580 ? FixedArray::kHeaderSize | |
581 : (FixedArray::kHeaderSize - kHeapObjectTag); | |
582 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); | |
583 Node* value = nullptr; | |
584 if (kind == FAST_ELEMENTS) { | |
585 value = LoadObjectField(elements, offset); | |
586 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); | |
587 } else { | |
588 Node* double_value = | |
589 LoadDoubleWithHoleCheck(elements, offset, &hole_element); | |
590 value = AllocateHeapNumberWithValue(double_value); | |
591 } | |
592 Node* result = CallJS(CodeFactory::Call(isolate()), context, | |
593 callbackfn, this_arg, value, tagged_index, o); | |
594 processor(a, tagged_index, result); | |
595 Goto(&one_element_done); | |
596 | |
597 Bind(&hole_element); | |
598 // Check if o's prototype change unexpectedly has elements after the | |
599 // callback in the case of a hole. | |
600 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, | |
601 array_changed); | |
602 | |
603 Bind(&one_element_done); | |
604 }, | |
605 1, mode, IndexAdvanceMode::kPost); | |
606 Comment("end VisitAllFastElementsOneKind"); | |
607 return last_index; | |
608 } | |
609 | |
610 void HandleFastElements(Node* context, Node* this_arg, Node* o, Node* len, | |
611 Node* callbackfn, CallResultProcessor processor, | |
612 Node* a, Variable& k, Label* slow) { | |
613 Label switch_on_elements_kind(this), fast_elements(this), | |
614 maybe_double_elements(this), fast_double_elements(this); | |
615 | |
616 Comment("begin HandleFastElements"); | |
617 // Non-smi lengths must use the slow path. | |
618 GotoIf(TaggedIsNotSmi(len), slow); | |
619 | |
620 BranchIfFastJSArray(o, context, | |
621 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, | |
622 &switch_on_elements_kind, slow); | |
623 | |
624 Bind(&switch_on_elements_kind); | |
625 // Select by ElementsKind | |
626 Node* o_map = LoadMap(o); | |
627 Node* bit_field2 = LoadMapBitField2(o_map); | |
628 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); | |
629 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | |
630 &maybe_double_elements, &fast_elements); | |
631 | |
632 ParameterMode mode = OptimalParameterMode(); | |
633 Bind(&fast_elements); | |
634 { | |
635 Label array_changed(this, Label::kDeferred); | |
636 Node* last_index = VisitAllFastElementsOneKind( | |
637 context, FAST_ELEMENTS, this_arg, o, len, callbackfn, processor, a, | |
638 &array_changed, mode); | |
639 | |
640 // No exception, return success | |
641 Return(a); | |
642 | |
643 Bind(&array_changed); | |
644 k.Bind(ParameterToTagged(last_index, mode)); | |
645 Goto(slow); | |
646 } | |
647 | |
648 Bind(&maybe_double_elements); | |
649 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)), | |
650 slow, &fast_double_elements); | |
651 | |
652 Bind(&fast_double_elements); | |
653 { | |
654 Label array_changed(this, Label::kDeferred); | |
655 Node* last_index = VisitAllFastElementsOneKind( | |
656 context, FAST_DOUBLE_ELEMENTS, this_arg, o, len, callbackfn, | |
657 processor, a, &array_changed, mode); | |
658 | |
659 // No exception, return success | |
660 Return(a); | |
661 | |
662 Bind(&array_changed); | |
663 k.Bind(ParameterToTagged(last_index, mode)); | |
664 Goto(slow); | |
665 } | |
666 } | |
667 }; | |
668 | |
669 TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) { | |
670 Node* receiver = Parameter(ForEachDescriptor::kReceiver); | |
671 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); | |
672 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); | |
673 Node* context = Parameter(ForEachDescriptor::kContext); | |
674 | |
675 GenerateArrayIteratingBuiltinBody( | |
676 "Array.prototype.forEach", receiver, callbackfn, this_arg, context, | |
677 [=](Node*, Node*) { return UndefinedConstant(); }, | |
678 [](Node* a, Node* p_k, Node* value) {}); | |
679 } | |
680 | |
681 TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) { | |
682 Node* receiver = Parameter(ForEachDescriptor::kReceiver); | |
683 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); | |
684 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); | |
685 Node* context = Parameter(ForEachDescriptor::kContext); | |
686 | |
687 GenerateArrayIteratingBuiltinBody( | |
688 "Array.prototype.every", receiver, callbackfn, this_arg, context, | |
689 [=](Node*, Node*) { return TrueConstant(); }, | |
690 [=](Node* a, Node* p_k, Node* value) { | |
691 Label true_continue(this), return_false(this); | |
692 BranchIfToBooleanIsTrue(value, &true_continue, &return_false); | |
693 Bind(&return_false); | |
694 Return(FalseConstant()); | |
695 Bind(&true_continue); | |
696 }); | |
697 } | |
698 | |
699 TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) { | |
700 Node* receiver = Parameter(ForEachDescriptor::kReceiver); | |
701 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); | |
702 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); | |
703 Node* context = Parameter(ForEachDescriptor::kContext); | |
704 | |
705 GenerateArrayIteratingBuiltinBody( | |
706 "Array.prototype.some", receiver, callbackfn, this_arg, context, | |
707 [=](Node*, Node*) { return FalseConstant(); }, | |
708 [=](Node* a, Node* p_k, Node* value) { | |
709 Label false_continue(this), return_true(this); | |
710 BranchIfToBooleanIsTrue(value, &return_true, &false_continue); | |
711 Bind(&return_true); | |
712 Return(TrueConstant()); | |
713 Bind(&false_continue); | |
714 }); | |
715 } | |
716 | |
717 BUILTIN(ArraySlice) { | 264 BUILTIN(ArraySlice) { |
718 HandleScope scope(isolate); | 265 HandleScope scope(isolate); |
719 Handle<Object> receiver = args.receiver(); | 266 Handle<Object> receiver = args.receiver(); |
720 int len = -1; | 267 int len = -1; |
721 int relative_start = 0; | 268 int relative_start = 0; |
722 int relative_end = 0; | 269 int relative_end = 0; |
723 | 270 |
724 if (receiver->IsJSArray()) { | 271 if (receiver->IsJSArray()) { |
725 DisallowHeapAllocation no_gc; | 272 DisallowHeapAllocation no_gc; |
726 JSArray* array = JSArray::cast(*receiver); | 273 JSArray* array = JSArray::cast(*receiver); |
(...skipping 958 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1685 isolate, species, Object::ArraySpeciesConstructor(isolate, receiver)); | 1232 isolate, species, Object::ArraySpeciesConstructor(isolate, receiver)); |
1686 if (*species == *isolate->array_function()) { | 1233 if (*species == *isolate->array_function()) { |
1687 if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) { | 1234 if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) { |
1688 return *result_array; | 1235 return *result_array; |
1689 } | 1236 } |
1690 if (isolate->has_pending_exception()) return isolate->heap()->exception(); | 1237 if (isolate->has_pending_exception()) return isolate->heap()->exception(); |
1691 } | 1238 } |
1692 return Slow_ArrayConcat(&args, species, isolate); | 1239 return Slow_ArrayConcat(&args, species, isolate); |
1693 } | 1240 } |
1694 | 1241 |
1695 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { | |
1696 Node* object = Parameter(1); | |
1697 Node* context = Parameter(4); | |
1698 | |
1699 Label call_runtime(this), return_true(this), return_false(this); | |
1700 | |
1701 GotoIf(TaggedIsSmi(object), &return_false); | |
1702 Node* instance_type = LoadInstanceType(object); | |
1703 | |
1704 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), | |
1705 &return_true); | |
1706 | |
1707 // TODO(verwaest): Handle proxies in-place. | |
1708 Branch(Word32Equal(instance_type, Int32Constant(JS_PROXY_TYPE)), | |
1709 &call_runtime, &return_false); | |
1710 | |
1711 Bind(&return_true); | |
1712 Return(BooleanConstant(true)); | |
1713 | |
1714 Bind(&return_false); | |
1715 Return(BooleanConstant(false)); | |
1716 | |
1717 Bind(&call_runtime); | |
1718 Return(CallRuntime(Runtime::kArrayIsArray, context, object)); | |
1719 } | |
1720 | |
1721 TF_BUILTIN(ArrayIncludes, CodeStubAssembler) { | |
1722 Node* const array = Parameter(0); | |
1723 Node* const search_element = Parameter(1); | |
1724 Node* const start_from = Parameter(2); | |
1725 Node* const context = Parameter(3 + 2); | |
1726 | |
1727 Variable index_var(this, MachineType::PointerRepresentation()); | |
1728 | |
1729 Label init_k(this), return_true(this), return_false(this), call_runtime(this); | |
1730 Label init_len(this), select_loop(this); | |
1731 | |
1732 index_var.Bind(IntPtrConstant(0)); | |
1733 | |
1734 // Take slow path if not a JSArray, if retrieving elements requires | |
1735 // traversing prototype, or if access checks are required. | |
1736 BranchIfFastJSArray(array, context, FastJSArrayAccessMode::INBOUNDS_READ, | |
1737 &init_len, &call_runtime); | |
1738 | |
1739 Bind(&init_len); | |
1740 // JSArray length is always an Smi for fast arrays. | |
1741 CSA_ASSERT(this, TaggedIsSmi(LoadObjectField(array, JSArray::kLengthOffset))); | |
1742 Node* const len = LoadAndUntagObjectField(array, JSArray::kLengthOffset); | |
1743 | |
1744 GotoIf(IsUndefined(start_from), &select_loop); | |
1745 | |
1746 // Bailout to slow path if startIndex is not an Smi. | |
1747 Branch(TaggedIsSmi(start_from), &init_k, &call_runtime); | |
1748 | |
1749 Bind(&init_k); | |
1750 CSA_ASSERT(this, TaggedIsSmi(start_from)); | |
1751 Node* const untagged_start_from = SmiToWord(start_from); | |
1752 index_var.Bind(Select( | |
1753 IntPtrGreaterThanOrEqual(untagged_start_from, IntPtrConstant(0)), | |
1754 [=]() { return untagged_start_from; }, | |
1755 [=]() { | |
1756 Node* const index = IntPtrAdd(len, untagged_start_from); | |
1757 return SelectConstant(IntPtrLessThan(index, IntPtrConstant(0)), | |
1758 IntPtrConstant(0), index, | |
1759 MachineType::PointerRepresentation()); | |
1760 }, | |
1761 MachineType::PointerRepresentation())); | |
1762 | |
1763 Goto(&select_loop); | |
1764 Bind(&select_loop); | |
1765 static int32_t kElementsKind[] = { | |
1766 FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS, | |
1767 FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS, | |
1768 }; | |
1769 | |
1770 Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this); | |
1771 Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects, | |
1772 &if_smiorobjects, &if_smiorobjects, | |
1773 &if_packed_doubles, &if_holey_doubles}; | |
1774 | |
1775 Node* map = LoadMap(array); | |
1776 Node* elements_kind = LoadMapElementsKind(map); | |
1777 Node* elements = LoadElements(array); | |
1778 Switch(elements_kind, &return_false, kElementsKind, element_kind_handlers, | |
1779 arraysize(kElementsKind)); | |
1780 | |
1781 Bind(&if_smiorobjects); | |
1782 { | |
1783 Variable search_num(this, MachineRepresentation::kFloat64); | |
1784 Label ident_loop(this, &index_var), heap_num_loop(this, &search_num), | |
1785 string_loop(this, &index_var), undef_loop(this, &index_var), | |
1786 not_smi(this), not_heap_num(this); | |
1787 | |
1788 GotoIfNot(TaggedIsSmi(search_element), ¬_smi); | |
1789 search_num.Bind(SmiToFloat64(search_element)); | |
1790 Goto(&heap_num_loop); | |
1791 | |
1792 Bind(¬_smi); | |
1793 GotoIf(WordEqual(search_element, UndefinedConstant()), &undef_loop); | |
1794 Node* map = LoadMap(search_element); | |
1795 GotoIfNot(IsHeapNumberMap(map), ¬_heap_num); | |
1796 search_num.Bind(LoadHeapNumberValue(search_element)); | |
1797 Goto(&heap_num_loop); | |
1798 | |
1799 Bind(¬_heap_num); | |
1800 Node* search_type = LoadMapInstanceType(map); | |
1801 GotoIf(IsStringInstanceType(search_type), &string_loop); | |
1802 Goto(&ident_loop); | |
1803 | |
1804 Bind(&ident_loop); | |
1805 { | |
1806 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); | |
1807 Node* element_k = LoadFixedArrayElement(elements, index_var.value()); | |
1808 GotoIf(WordEqual(element_k, search_element), &return_true); | |
1809 | |
1810 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); | |
1811 Goto(&ident_loop); | |
1812 } | |
1813 | |
1814 Bind(&undef_loop); | |
1815 { | |
1816 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); | |
1817 Node* element_k = LoadFixedArrayElement(elements, index_var.value()); | |
1818 GotoIf(WordEqual(element_k, UndefinedConstant()), &return_true); | |
1819 GotoIf(WordEqual(element_k, TheHoleConstant()), &return_true); | |
1820 | |
1821 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); | |
1822 Goto(&undef_loop); | |
1823 } | |
1824 | |
1825 Bind(&heap_num_loop); | |
1826 { | |
1827 Label nan_loop(this, &index_var), not_nan_loop(this, &index_var); | |
1828 BranchIfFloat64IsNaN(search_num.value(), &nan_loop, ¬_nan_loop); | |
1829 | |
1830 Bind(¬_nan_loop); | |
1831 { | |
1832 Label continue_loop(this), not_smi(this); | |
1833 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); | |
1834 Node* element_k = LoadFixedArrayElement(elements, index_var.value()); | |
1835 GotoIfNot(TaggedIsSmi(element_k), ¬_smi); | |
1836 Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)), | |
1837 &return_true, &continue_loop); | |
1838 | |
1839 Bind(¬_smi); | |
1840 GotoIfNot(IsHeapNumber(element_k), &continue_loop); | |
1841 Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)), | |
1842 &return_true, &continue_loop); | |
1843 | |
1844 Bind(&continue_loop); | |
1845 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); | |
1846 Goto(¬_nan_loop); | |
1847 } | |
1848 | |
1849 Bind(&nan_loop); | |
1850 { | |
1851 Label continue_loop(this); | |
1852 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); | |
1853 Node* element_k = LoadFixedArrayElement(elements, index_var.value()); | |
1854 GotoIf(TaggedIsSmi(element_k), &continue_loop); | |
1855 GotoIfNot(IsHeapNumber(element_k), &continue_loop); | |
1856 BranchIfFloat64IsNaN(LoadHeapNumberValue(element_k), &return_true, | |
1857 &continue_loop); | |
1858 | |
1859 Bind(&continue_loop); | |
1860 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); | |
1861 Goto(&nan_loop); | |
1862 } | |
1863 } | |
1864 | |
1865 Bind(&string_loop); | |
1866 { | |
1867 Label continue_loop(this); | |
1868 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); | |
1869 Node* element_k = LoadFixedArrayElement(elements, index_var.value()); | |
1870 GotoIf(TaggedIsSmi(element_k), &continue_loop); | |
1871 GotoIfNot(IsStringInstanceType(LoadInstanceType(element_k)), | |
1872 &continue_loop); | |
1873 | |
1874 // TODO(bmeurer): Consider inlining the StringEqual logic here. | |
1875 Node* result = CallStub(CodeFactory::StringEqual(isolate()), context, | |
1876 search_element, element_k); | |
1877 Branch(WordEqual(BooleanConstant(true), result), &return_true, | |
1878 &continue_loop); | |
1879 | |
1880 Bind(&continue_loop); | |
1881 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); | |
1882 Goto(&string_loop); | |
1883 } | |
1884 } | |
1885 | |
1886 Bind(&if_packed_doubles); | |
1887 { | |
1888 Label nan_loop(this, &index_var), not_nan_loop(this, &index_var), | |
1889 hole_loop(this, &index_var), search_notnan(this); | |
1890 Variable search_num(this, MachineRepresentation::kFloat64); | |
1891 | |
1892 GotoIfNot(TaggedIsSmi(search_element), &search_notnan); | |
1893 search_num.Bind(SmiToFloat64(search_element)); | |
1894 Goto(¬_nan_loop); | |
1895 | |
1896 Bind(&search_notnan); | |
1897 GotoIfNot(IsHeapNumber(search_element), &return_false); | |
1898 | |
1899 search_num.Bind(LoadHeapNumberValue(search_element)); | |
1900 | |
1901 BranchIfFloat64IsNaN(search_num.value(), &nan_loop, ¬_nan_loop); | |
1902 | |
1903 // Search for HeapNumber | |
1904 Bind(¬_nan_loop); | |
1905 { | |
1906 Label continue_loop(this); | |
1907 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); | |
1908 Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(), | |
1909 MachineType::Float64()); | |
1910 Branch(Float64Equal(element_k, search_num.value()), &return_true, | |
1911 &continue_loop); | |
1912 Bind(&continue_loop); | |
1913 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); | |
1914 Goto(¬_nan_loop); | |
1915 } | |
1916 | |
1917 // Search for NaN | |
1918 Bind(&nan_loop); | |
1919 { | |
1920 Label continue_loop(this); | |
1921 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); | |
1922 Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(), | |
1923 MachineType::Float64()); | |
1924 BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop); | |
1925 Bind(&continue_loop); | |
1926 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); | |
1927 Goto(&nan_loop); | |
1928 } | |
1929 } | |
1930 | |
1931 Bind(&if_holey_doubles); | |
1932 { | |
1933 Label nan_loop(this, &index_var), not_nan_loop(this, &index_var), | |
1934 hole_loop(this, &index_var), search_notnan(this); | |
1935 Variable search_num(this, MachineRepresentation::kFloat64); | |
1936 | |
1937 GotoIfNot(TaggedIsSmi(search_element), &search_notnan); | |
1938 search_num.Bind(SmiToFloat64(search_element)); | |
1939 Goto(¬_nan_loop); | |
1940 | |
1941 Bind(&search_notnan); | |
1942 GotoIf(WordEqual(search_element, UndefinedConstant()), &hole_loop); | |
1943 GotoIfNot(IsHeapNumber(search_element), &return_false); | |
1944 | |
1945 search_num.Bind(LoadHeapNumberValue(search_element)); | |
1946 | |
1947 BranchIfFloat64IsNaN(search_num.value(), &nan_loop, ¬_nan_loop); | |
1948 | |
1949 // Search for HeapNumber | |
1950 Bind(¬_nan_loop); | |
1951 { | |
1952 Label continue_loop(this); | |
1953 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); | |
1954 | |
1955 // Load double value or continue if it contains a double hole. | |
1956 Node* element_k = LoadFixedDoubleArrayElement( | |
1957 elements, index_var.value(), MachineType::Float64(), 0, | |
1958 INTPTR_PARAMETERS, &continue_loop); | |
1959 | |
1960 Branch(Float64Equal(element_k, search_num.value()), &return_true, | |
1961 &continue_loop); | |
1962 Bind(&continue_loop); | |
1963 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); | |
1964 Goto(¬_nan_loop); | |
1965 } | |
1966 | |
1967 // Search for NaN | |
1968 Bind(&nan_loop); | |
1969 { | |
1970 Label continue_loop(this); | |
1971 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); | |
1972 | |
1973 // Load double value or continue if it contains a double hole. | |
1974 Node* element_k = LoadFixedDoubleArrayElement( | |
1975 elements, index_var.value(), MachineType::Float64(), 0, | |
1976 INTPTR_PARAMETERS, &continue_loop); | |
1977 | |
1978 BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop); | |
1979 Bind(&continue_loop); | |
1980 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); | |
1981 Goto(&nan_loop); | |
1982 } | |
1983 | |
1984 // Search for the Hole | |
1985 Bind(&hole_loop); | |
1986 { | |
1987 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); | |
1988 | |
1989 // Check if the element is a double hole, but don't load it. | |
1990 LoadFixedDoubleArrayElement(elements, index_var.value(), | |
1991 MachineType::None(), 0, INTPTR_PARAMETERS, | |
1992 &return_true); | |
1993 | |
1994 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); | |
1995 Goto(&hole_loop); | |
1996 } | |
1997 } | |
1998 | |
1999 Bind(&return_true); | |
2000 Return(TrueConstant()); | |
2001 | |
2002 Bind(&return_false); | |
2003 Return(FalseConstant()); | |
2004 | |
2005 Bind(&call_runtime); | |
2006 Return(CallRuntime(Runtime::kArrayIncludes_Slow, context, array, | |
2007 search_element, start_from)); | |
2008 } | |
2009 | |
2010 TF_BUILTIN(ArrayIndexOf, CodeStubAssembler) { | |
2011 Node* array = Parameter(0); | |
2012 Node* search_element = Parameter(1); | |
2013 Node* start_from = Parameter(2); | |
2014 Node* context = Parameter(3 + 2); | |
2015 | |
2016 Node* intptr_zero = IntPtrConstant(0); | |
2017 Node* intptr_one = IntPtrConstant(1); | |
2018 | |
2019 Variable len_var(this, MachineType::PointerRepresentation()), | |
2020 index_var(this, MachineType::PointerRepresentation()), | |
2021 start_from_var(this, MachineType::PointerRepresentation()); | |
2022 | |
2023 Label init_k(this), return_found(this), return_not_found(this), | |
2024 call_runtime(this); | |
2025 | |
2026 Label init_len(this); | |
2027 | |
2028 index_var.Bind(intptr_zero); | |
2029 len_var.Bind(intptr_zero); | |
2030 | |
2031 // Take slow path if not a JSArray, if retrieving elements requires | |
2032 // traversing prototype, or if access checks are required. | |
2033 BranchIfFastJSArray(array, context, FastJSArrayAccessMode::INBOUNDS_READ, | |
2034 &init_len, &call_runtime); | |
2035 | |
2036 Bind(&init_len); | |
2037 { | |
2038 // JSArray length is always an Smi for fast arrays. | |
2039 CSA_ASSERT(this, | |
2040 TaggedIsSmi(LoadObjectField(array, JSArray::kLengthOffset))); | |
2041 Node* len = LoadAndUntagObjectField(array, JSArray::kLengthOffset); | |
2042 | |
2043 len_var.Bind(len); | |
2044 Branch(WordEqual(len_var.value(), intptr_zero), &return_not_found, &init_k); | |
2045 } | |
2046 | |
2047 Bind(&init_k); | |
2048 { | |
2049 // For now only deal with undefined and Smis here; we must be really careful | |
2050 // with side-effects from the ToInteger conversion as the side-effects might | |
2051 // render our assumptions about the receiver being a fast JSArray and the | |
2052 // length invalid. | |
2053 Label done(this), init_k_smi(this), init_k_other(this), init_k_zero(this), | |
2054 init_k_n(this); | |
2055 Branch(TaggedIsSmi(start_from), &init_k_smi, &init_k_other); | |
2056 | |
2057 Bind(&init_k_smi); | |
2058 { | |
2059 // The fromIndex is a Smi. | |
2060 start_from_var.Bind(SmiUntag(start_from)); | |
2061 Goto(&init_k_n); | |
2062 } | |
2063 | |
2064 Bind(&init_k_other); | |
2065 { | |
2066 // The fromIndex must be undefined then, otherwise bailout and let the | |
2067 // runtime deal with the full ToInteger conversion. | |
2068 GotoIfNot(IsUndefined(start_from), &call_runtime); | |
2069 start_from_var.Bind(intptr_zero); | |
2070 Goto(&init_k_n); | |
2071 } | |
2072 | |
2073 Bind(&init_k_n); | |
2074 { | |
2075 Label if_positive(this), if_negative(this), done(this); | |
2076 Branch(IntPtrLessThan(start_from_var.value(), intptr_zero), &if_negative, | |
2077 &if_positive); | |
2078 | |
2079 Bind(&if_positive); | |
2080 { | |
2081 index_var.Bind(start_from_var.value()); | |
2082 Goto(&done); | |
2083 } | |
2084 | |
2085 Bind(&if_negative); | |
2086 { | |
2087 index_var.Bind(IntPtrAdd(len_var.value(), start_from_var.value())); | |
2088 Branch(IntPtrLessThan(index_var.value(), intptr_zero), &init_k_zero, | |
2089 &done); | |
2090 } | |
2091 | |
2092 Bind(&init_k_zero); | |
2093 { | |
2094 index_var.Bind(intptr_zero); | |
2095 Goto(&done); | |
2096 } | |
2097 | |
2098 Bind(&done); | |
2099 } | |
2100 } | |
2101 | |
2102 static int32_t kElementsKind[] = { | |
2103 FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS, | |
2104 FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS, | |
2105 }; | |
2106 | |
2107 Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this); | |
2108 Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects, | |
2109 &if_smiorobjects, &if_smiorobjects, | |
2110 &if_packed_doubles, &if_holey_doubles}; | |
2111 | |
2112 Node* map = LoadMap(array); | |
2113 Node* elements_kind = LoadMapElementsKind(map); | |
2114 Node* elements = LoadElements(array); | |
2115 Switch(elements_kind, &return_not_found, kElementsKind, element_kind_handlers, | |
2116 arraysize(kElementsKind)); | |
2117 | |
2118 Bind(&if_smiorobjects); | |
2119 { | |
2120 Variable search_num(this, MachineRepresentation::kFloat64); | |
2121 Label ident_loop(this, &index_var), heap_num_loop(this, &search_num), | |
2122 string_loop(this, &index_var), not_smi(this), not_heap_num(this); | |
2123 | |
2124 GotoIfNot(TaggedIsSmi(search_element), ¬_smi); | |
2125 search_num.Bind(SmiToFloat64(search_element)); | |
2126 Goto(&heap_num_loop); | |
2127 | |
2128 Bind(¬_smi); | |
2129 Node* map = LoadMap(search_element); | |
2130 GotoIfNot(IsHeapNumberMap(map), ¬_heap_num); | |
2131 search_num.Bind(LoadHeapNumberValue(search_element)); | |
2132 Goto(&heap_num_loop); | |
2133 | |
2134 Bind(¬_heap_num); | |
2135 Node* search_type = LoadMapInstanceType(map); | |
2136 GotoIf(IsStringInstanceType(search_type), &string_loop); | |
2137 Goto(&ident_loop); | |
2138 | |
2139 Bind(&ident_loop); | |
2140 { | |
2141 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), | |
2142 &return_not_found); | |
2143 Node* element_k = LoadFixedArrayElement(elements, index_var.value()); | |
2144 GotoIf(WordEqual(element_k, search_element), &return_found); | |
2145 | |
2146 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); | |
2147 Goto(&ident_loop); | |
2148 } | |
2149 | |
2150 Bind(&heap_num_loop); | |
2151 { | |
2152 Label not_nan_loop(this, &index_var); | |
2153 BranchIfFloat64IsNaN(search_num.value(), &return_not_found, | |
2154 ¬_nan_loop); | |
2155 | |
2156 Bind(¬_nan_loop); | |
2157 { | |
2158 Label continue_loop(this), not_smi(this); | |
2159 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), | |
2160 &return_not_found); | |
2161 Node* element_k = LoadFixedArrayElement(elements, index_var.value()); | |
2162 GotoIfNot(TaggedIsSmi(element_k), ¬_smi); | |
2163 Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)), | |
2164 &return_found, &continue_loop); | |
2165 | |
2166 Bind(¬_smi); | |
2167 GotoIfNot(IsHeapNumber(element_k), &continue_loop); | |
2168 Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)), | |
2169 &return_found, &continue_loop); | |
2170 | |
2171 Bind(&continue_loop); | |
2172 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); | |
2173 Goto(¬_nan_loop); | |
2174 } | |
2175 } | |
2176 | |
2177 Bind(&string_loop); | |
2178 { | |
2179 Label continue_loop(this); | |
2180 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), | |
2181 &return_not_found); | |
2182 Node* element_k = LoadFixedArrayElement(elements, index_var.value()); | |
2183 GotoIf(TaggedIsSmi(element_k), &continue_loop); | |
2184 GotoIfNot(IsString(element_k), &continue_loop); | |
2185 | |
2186 // TODO(bmeurer): Consider inlining the StringEqual logic here. | |
2187 Callable callable = CodeFactory::StringEqual(isolate()); | |
2188 Node* result = CallStub(callable, context, search_element, element_k); | |
2189 Branch(WordEqual(BooleanConstant(true), result), &return_found, | |
2190 &continue_loop); | |
2191 | |
2192 Bind(&continue_loop); | |
2193 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); | |
2194 Goto(&string_loop); | |
2195 } | |
2196 } | |
2197 | |
2198 Bind(&if_packed_doubles); | |
2199 { | |
2200 Label not_nan_loop(this, &index_var), search_notnan(this); | |
2201 Variable search_num(this, MachineRepresentation::kFloat64); | |
2202 | |
2203 GotoIfNot(TaggedIsSmi(search_element), &search_notnan); | |
2204 search_num.Bind(SmiToFloat64(search_element)); | |
2205 Goto(¬_nan_loop); | |
2206 | |
2207 Bind(&search_notnan); | |
2208 GotoIfNot(IsHeapNumber(search_element), &return_not_found); | |
2209 | |
2210 search_num.Bind(LoadHeapNumberValue(search_element)); | |
2211 | |
2212 BranchIfFloat64IsNaN(search_num.value(), &return_not_found, ¬_nan_loop); | |
2213 | |
2214 // Search for HeapNumber | |
2215 Bind(¬_nan_loop); | |
2216 { | |
2217 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), | |
2218 &return_not_found); | |
2219 Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(), | |
2220 MachineType::Float64()); | |
2221 GotoIf(Float64Equal(element_k, search_num.value()), &return_found); | |
2222 | |
2223 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); | |
2224 Goto(¬_nan_loop); | |
2225 } | |
2226 } | |
2227 | |
2228 Bind(&if_holey_doubles); | |
2229 { | |
2230 Label not_nan_loop(this, &index_var), search_notnan(this); | |
2231 Variable search_num(this, MachineRepresentation::kFloat64); | |
2232 | |
2233 GotoIfNot(TaggedIsSmi(search_element), &search_notnan); | |
2234 search_num.Bind(SmiToFloat64(search_element)); | |
2235 Goto(¬_nan_loop); | |
2236 | |
2237 Bind(&search_notnan); | |
2238 GotoIfNot(IsHeapNumber(search_element), &return_not_found); | |
2239 | |
2240 search_num.Bind(LoadHeapNumberValue(search_element)); | |
2241 | |
2242 BranchIfFloat64IsNaN(search_num.value(), &return_not_found, ¬_nan_loop); | |
2243 | |
2244 // Search for HeapNumber | |
2245 Bind(¬_nan_loop); | |
2246 { | |
2247 Label continue_loop(this); | |
2248 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), | |
2249 &return_not_found); | |
2250 | |
2251 // Load double value or continue if it contains a double hole. | |
2252 Node* element_k = LoadFixedDoubleArrayElement( | |
2253 elements, index_var.value(), MachineType::Float64(), 0, | |
2254 INTPTR_PARAMETERS, &continue_loop); | |
2255 | |
2256 Branch(Float64Equal(element_k, search_num.value()), &return_found, | |
2257 &continue_loop); | |
2258 Bind(&continue_loop); | |
2259 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); | |
2260 Goto(¬_nan_loop); | |
2261 } | |
2262 } | |
2263 | |
2264 Bind(&return_found); | |
2265 Return(SmiTag(index_var.value())); | |
2266 | |
2267 Bind(&return_not_found); | |
2268 Return(NumberConstant(-1)); | |
2269 | |
2270 Bind(&call_runtime); | |
2271 Return(CallRuntime(Runtime::kArrayIndexOf, context, array, search_element, | |
2272 start_from)); | |
2273 } | |
2274 | |
2275 class ArrayPrototypeIterationAssembler : public CodeStubAssembler { | |
2276 public: | |
2277 explicit ArrayPrototypeIterationAssembler(compiler::CodeAssemblerState* state) | |
2278 : CodeStubAssembler(state) {} | |
2279 | |
2280 protected: | |
2281 void Generate_ArrayPrototypeIterationMethod(IterationKind iteration_kind) { | |
2282 Node* receiver = Parameter(0); | |
2283 Node* context = Parameter(3); | |
2284 | |
2285 Variable var_array(this, MachineRepresentation::kTagged); | |
2286 Variable var_map(this, MachineRepresentation::kTagged); | |
2287 Variable var_type(this, MachineRepresentation::kWord32); | |
2288 | |
2289 Label if_isnotobject(this, Label::kDeferred); | |
2290 Label create_array_iterator(this); | |
2291 | |
2292 GotoIf(TaggedIsSmi(receiver), &if_isnotobject); | |
2293 var_array.Bind(receiver); | |
2294 var_map.Bind(LoadMap(receiver)); | |
2295 var_type.Bind(LoadMapInstanceType(var_map.value())); | |
2296 Branch(IsJSReceiverInstanceType(var_type.value()), &create_array_iterator, | |
2297 &if_isnotobject); | |
2298 | |
2299 Bind(&if_isnotobject); | |
2300 { | |
2301 Callable callable = CodeFactory::ToObject(isolate()); | |
2302 Node* result = CallStub(callable, context, receiver); | |
2303 var_array.Bind(result); | |
2304 var_map.Bind(LoadMap(result)); | |
2305 var_type.Bind(LoadMapInstanceType(var_map.value())); | |
2306 Goto(&create_array_iterator); | |
2307 } | |
2308 | |
2309 Bind(&create_array_iterator); | |
2310 Return(CreateArrayIterator(var_array.value(), var_map.value(), | |
2311 var_type.value(), context, iteration_kind)); | |
2312 } | |
2313 }; | |
2314 | |
2315 TF_BUILTIN(ArrayPrototypeValues, ArrayPrototypeIterationAssembler) { | |
2316 Generate_ArrayPrototypeIterationMethod(IterationKind::kValues); | |
2317 } | |
2318 | |
2319 TF_BUILTIN(ArrayPrototypeEntries, ArrayPrototypeIterationAssembler) { | |
2320 Generate_ArrayPrototypeIterationMethod(IterationKind::kEntries); | |
2321 } | |
2322 | |
2323 TF_BUILTIN(ArrayPrototypeKeys, ArrayPrototypeIterationAssembler) { | |
2324 Generate_ArrayPrototypeIterationMethod(IterationKind::kKeys); | |
2325 } | |
2326 | |
2327 TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) { | |
2328 Handle<String> operation = factory()->NewStringFromAsciiChecked( | |
2329 "Array Iterator.prototype.next", TENURED); | |
2330 | |
2331 Node* iterator = Parameter(0); | |
2332 Node* context = Parameter(3); | |
2333 | |
2334 Variable var_value(this, MachineRepresentation::kTagged); | |
2335 Variable var_done(this, MachineRepresentation::kTagged); | |
2336 | |
2337 // Required, or else `throw_bad_receiver` fails a DCHECK due to these | |
2338 // variables not being bound along all paths, despite not being used. | |
2339 var_done.Bind(TrueConstant()); | |
2340 var_value.Bind(UndefinedConstant()); | |
2341 | |
2342 Label throw_bad_receiver(this, Label::kDeferred); | |
2343 Label set_done(this); | |
2344 Label allocate_key_result(this); | |
2345 Label allocate_entry_if_needed(this); | |
2346 Label allocate_iterator_result(this); | |
2347 Label generic_values(this); | |
2348 | |
2349 // If O does not have all of the internal slots of an Array Iterator Instance | |
2350 // (22.1.5.3), throw a TypeError exception | |
2351 GotoIf(TaggedIsSmi(iterator), &throw_bad_receiver); | |
2352 Node* instance_type = LoadInstanceType(iterator); | |
2353 GotoIf( | |
2354 Uint32LessThan( | |
2355 Int32Constant(LAST_ARRAY_ITERATOR_TYPE - FIRST_ARRAY_ITERATOR_TYPE), | |
2356 Int32Sub(instance_type, Int32Constant(FIRST_ARRAY_ITERATOR_TYPE))), | |
2357 &throw_bad_receiver); | |
2358 | |
2359 // Let a be O.[[IteratedObject]]. | |
2360 Node* array = | |
2361 LoadObjectField(iterator, JSArrayIterator::kIteratedObjectOffset); | |
2362 | |
2363 // Let index be O.[[ArrayIteratorNextIndex]]. | |
2364 Node* index = LoadObjectField(iterator, JSArrayIterator::kNextIndexOffset); | |
2365 Node* orig_map = | |
2366 LoadObjectField(iterator, JSArrayIterator::kIteratedObjectMapOffset); | |
2367 Node* array_map = LoadMap(array); | |
2368 | |
2369 Label if_isfastarray(this), if_isnotfastarray(this), | |
2370 if_isdetached(this, Label::kDeferred); | |
2371 | |
2372 Branch(WordEqual(orig_map, array_map), &if_isfastarray, &if_isnotfastarray); | |
2373 | |
2374 Bind(&if_isfastarray); | |
2375 { | |
2376 CSA_ASSERT(this, Word32Equal(LoadMapInstanceType(array_map), | |
2377 Int32Constant(JS_ARRAY_TYPE))); | |
2378 | |
2379 Node* length = LoadObjectField(array, JSArray::kLengthOffset); | |
2380 | |
2381 CSA_ASSERT(this, TaggedIsSmi(length)); | |
2382 CSA_ASSERT(this, TaggedIsSmi(index)); | |
2383 | |
2384 GotoIfNot(SmiBelow(index, length), &set_done); | |
2385 | |
2386 Node* one = SmiConstant(Smi::FromInt(1)); | |
2387 StoreObjectFieldNoWriteBarrier(iterator, JSArrayIterator::kNextIndexOffset, | |
2388 SmiAdd(index, one)); | |
2389 | |
2390 var_done.Bind(FalseConstant()); | |
2391 Node* elements = LoadElements(array); | |
2392 | |
2393 static int32_t kInstanceType[] = { | |
2394 JS_FAST_ARRAY_KEY_ITERATOR_TYPE, | |
2395 JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2396 JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2397 JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2398 JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2399 JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2400 JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2401 JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE, | |
2402 JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE, | |
2403 JS_FAST_ARRAY_VALUE_ITERATOR_TYPE, | |
2404 JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE, | |
2405 JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE, | |
2406 JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE, | |
2407 }; | |
2408 | |
2409 Label packed_object_values(this), holey_object_values(this), | |
2410 packed_double_values(this), holey_double_values(this); | |
2411 Label* kInstanceTypeHandlers[] = { | |
2412 &allocate_key_result, &packed_object_values, &holey_object_values, | |
2413 &packed_object_values, &holey_object_values, &packed_double_values, | |
2414 &holey_double_values, &packed_object_values, &holey_object_values, | |
2415 &packed_object_values, &holey_object_values, &packed_double_values, | |
2416 &holey_double_values}; | |
2417 | |
2418 Switch(instance_type, &throw_bad_receiver, kInstanceType, | |
2419 kInstanceTypeHandlers, arraysize(kInstanceType)); | |
2420 | |
2421 Bind(&packed_object_values); | |
2422 { | |
2423 var_value.Bind(LoadFixedArrayElement(elements, index, 0, SMI_PARAMETERS)); | |
2424 Goto(&allocate_entry_if_needed); | |
2425 } | |
2426 | |
2427 Bind(&packed_double_values); | |
2428 { | |
2429 Node* value = LoadFixedDoubleArrayElement( | |
2430 elements, index, MachineType::Float64(), 0, SMI_PARAMETERS); | |
2431 var_value.Bind(AllocateHeapNumberWithValue(value)); | |
2432 Goto(&allocate_entry_if_needed); | |
2433 } | |
2434 | |
2435 Bind(&holey_object_values); | |
2436 { | |
2437 // Check the array_protector cell, and take the slow path if it's invalid. | |
2438 Node* invalid = SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid)); | |
2439 Node* cell = LoadRoot(Heap::kArrayProtectorRootIndex); | |
2440 Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); | |
2441 GotoIf(WordEqual(cell_value, invalid), &generic_values); | |
2442 | |
2443 var_value.Bind(UndefinedConstant()); | |
2444 Node* value = LoadFixedArrayElement(elements, index, 0, SMI_PARAMETERS); | |
2445 GotoIf(WordEqual(value, TheHoleConstant()), &allocate_entry_if_needed); | |
2446 var_value.Bind(value); | |
2447 Goto(&allocate_entry_if_needed); | |
2448 } | |
2449 | |
2450 Bind(&holey_double_values); | |
2451 { | |
2452 // Check the array_protector cell, and take the slow path if it's invalid. | |
2453 Node* invalid = SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid)); | |
2454 Node* cell = LoadRoot(Heap::kArrayProtectorRootIndex); | |
2455 Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); | |
2456 GotoIf(WordEqual(cell_value, invalid), &generic_values); | |
2457 | |
2458 var_value.Bind(UndefinedConstant()); | |
2459 Node* value = LoadFixedDoubleArrayElement( | |
2460 elements, index, MachineType::Float64(), 0, SMI_PARAMETERS, | |
2461 &allocate_entry_if_needed); | |
2462 var_value.Bind(AllocateHeapNumberWithValue(value)); | |
2463 Goto(&allocate_entry_if_needed); | |
2464 } | |
2465 } | |
2466 | |
2467 Bind(&if_isnotfastarray); | |
2468 { | |
2469 Label if_istypedarray(this), if_isgeneric(this); | |
2470 | |
2471 // If a is undefined, return CreateIterResultObject(undefined, true) | |
2472 GotoIf(WordEqual(array, UndefinedConstant()), &allocate_iterator_result); | |
2473 | |
2474 Node* array_type = LoadInstanceType(array); | |
2475 Branch(Word32Equal(array_type, Int32Constant(JS_TYPED_ARRAY_TYPE)), | |
2476 &if_istypedarray, &if_isgeneric); | |
2477 | |
2478 Bind(&if_isgeneric); | |
2479 { | |
2480 Label if_wasfastarray(this); | |
2481 | |
2482 Node* length = nullptr; | |
2483 { | |
2484 Variable var_length(this, MachineRepresentation::kTagged); | |
2485 Label if_isarray(this), if_isnotarray(this), done(this); | |
2486 Branch(Word32Equal(array_type, Int32Constant(JS_ARRAY_TYPE)), | |
2487 &if_isarray, &if_isnotarray); | |
2488 | |
2489 Bind(&if_isarray); | |
2490 { | |
2491 var_length.Bind(LoadObjectField(array, JSArray::kLengthOffset)); | |
2492 | |
2493 // Invalidate protector cell if needed | |
2494 Branch(WordNotEqual(orig_map, UndefinedConstant()), &if_wasfastarray, | |
2495 &done); | |
2496 | |
2497 Bind(&if_wasfastarray); | |
2498 { | |
2499 Label if_invalid(this, Label::kDeferred); | |
2500 // A fast array iterator transitioned to a slow iterator during | |
2501 // iteration. Invalidate fast_array_iteration_prtoector cell to | |
2502 // prevent potential deopt loops. | |
2503 StoreObjectFieldNoWriteBarrier( | |
2504 iterator, JSArrayIterator::kIteratedObjectMapOffset, | |
2505 UndefinedConstant()); | |
2506 GotoIf(Uint32LessThanOrEqual( | |
2507 instance_type, | |
2508 Int32Constant(JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)), | |
2509 &done); | |
2510 | |
2511 Node* invalid = | |
2512 SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid)); | |
2513 Node* cell = LoadRoot(Heap::kFastArrayIterationProtectorRootIndex); | |
2514 StoreObjectFieldNoWriteBarrier(cell, Cell::kValueOffset, invalid); | |
2515 Goto(&done); | |
2516 } | |
2517 } | |
2518 | |
2519 Bind(&if_isnotarray); | |
2520 { | |
2521 Node* length = | |
2522 GetProperty(context, array, factory()->length_string()); | |
2523 Callable to_length = CodeFactory::ToLength(isolate()); | |
2524 var_length.Bind(CallStub(to_length, context, length)); | |
2525 Goto(&done); | |
2526 } | |
2527 | |
2528 Bind(&done); | |
2529 length = var_length.value(); | |
2530 } | |
2531 | |
2532 GotoUnlessNumberLessThan(index, length, &set_done); | |
2533 | |
2534 StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset, | |
2535 NumberInc(index)); | |
2536 var_done.Bind(FalseConstant()); | |
2537 | |
2538 Branch( | |
2539 Uint32LessThanOrEqual( | |
2540 instance_type, Int32Constant(JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)), | |
2541 &allocate_key_result, &generic_values); | |
2542 | |
2543 Bind(&generic_values); | |
2544 { | |
2545 var_value.Bind(GetProperty(context, array, index)); | |
2546 Goto(&allocate_entry_if_needed); | |
2547 } | |
2548 } | |
2549 | |
2550 Bind(&if_istypedarray); | |
2551 { | |
2552 Node* buffer = LoadObjectField(array, JSTypedArray::kBufferOffset); | |
2553 GotoIf(IsDetachedBuffer(buffer), &if_isdetached); | |
2554 | |
2555 Node* length = LoadObjectField(array, JSTypedArray::kLengthOffset); | |
2556 | |
2557 CSA_ASSERT(this, TaggedIsSmi(length)); | |
2558 CSA_ASSERT(this, TaggedIsSmi(index)); | |
2559 | |
2560 GotoIfNot(SmiBelow(index, length), &set_done); | |
2561 | |
2562 Node* one = SmiConstant(1); | |
2563 StoreObjectFieldNoWriteBarrier( | |
2564 iterator, JSArrayIterator::kNextIndexOffset, SmiAdd(index, one)); | |
2565 var_done.Bind(FalseConstant()); | |
2566 | |
2567 Node* elements = LoadElements(array); | |
2568 Node* base_ptr = | |
2569 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); | |
2570 Node* external_ptr = | |
2571 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, | |
2572 MachineType::Pointer()); | |
2573 Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr); | |
2574 | |
2575 static int32_t kInstanceType[] = { | |
2576 JS_TYPED_ARRAY_KEY_ITERATOR_TYPE, | |
2577 JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2578 JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2579 JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2580 JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2581 JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2582 JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2583 JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2584 JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2585 JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE, | |
2586 JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE, | |
2587 JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE, | |
2588 JS_INT8_ARRAY_VALUE_ITERATOR_TYPE, | |
2589 JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE, | |
2590 JS_INT16_ARRAY_VALUE_ITERATOR_TYPE, | |
2591 JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE, | |
2592 JS_INT32_ARRAY_VALUE_ITERATOR_TYPE, | |
2593 JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE, | |
2594 JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE, | |
2595 }; | |
2596 | |
2597 Label uint8_values(this), int8_values(this), uint16_values(this), | |
2598 int16_values(this), uint32_values(this), int32_values(this), | |
2599 float32_values(this), float64_values(this); | |
2600 Label* kInstanceTypeHandlers[] = { | |
2601 &allocate_key_result, &uint8_values, &uint8_values, | |
2602 &int8_values, &uint16_values, &int16_values, | |
2603 &uint32_values, &int32_values, &float32_values, | |
2604 &float64_values, &uint8_values, &uint8_values, | |
2605 &int8_values, &uint16_values, &int16_values, | |
2606 &uint32_values, &int32_values, &float32_values, | |
2607 &float64_values, | |
2608 }; | |
2609 | |
2610 var_done.Bind(FalseConstant()); | |
2611 Switch(instance_type, &throw_bad_receiver, kInstanceType, | |
2612 kInstanceTypeHandlers, arraysize(kInstanceType)); | |
2613 | |
2614 Bind(&uint8_values); | |
2615 { | |
2616 Node* value_uint8 = LoadFixedTypedArrayElement( | |
2617 data_ptr, index, UINT8_ELEMENTS, SMI_PARAMETERS); | |
2618 var_value.Bind(SmiFromWord32(value_uint8)); | |
2619 Goto(&allocate_entry_if_needed); | |
2620 } | |
2621 Bind(&int8_values); | |
2622 { | |
2623 Node* value_int8 = LoadFixedTypedArrayElement( | |
2624 data_ptr, index, INT8_ELEMENTS, SMI_PARAMETERS); | |
2625 var_value.Bind(SmiFromWord32(value_int8)); | |
2626 Goto(&allocate_entry_if_needed); | |
2627 } | |
2628 Bind(&uint16_values); | |
2629 { | |
2630 Node* value_uint16 = LoadFixedTypedArrayElement( | |
2631 data_ptr, index, UINT16_ELEMENTS, SMI_PARAMETERS); | |
2632 var_value.Bind(SmiFromWord32(value_uint16)); | |
2633 Goto(&allocate_entry_if_needed); | |
2634 } | |
2635 Bind(&int16_values); | |
2636 { | |
2637 Node* value_int16 = LoadFixedTypedArrayElement( | |
2638 data_ptr, index, INT16_ELEMENTS, SMI_PARAMETERS); | |
2639 var_value.Bind(SmiFromWord32(value_int16)); | |
2640 Goto(&allocate_entry_if_needed); | |
2641 } | |
2642 Bind(&uint32_values); | |
2643 { | |
2644 Node* value_uint32 = LoadFixedTypedArrayElement( | |
2645 data_ptr, index, UINT32_ELEMENTS, SMI_PARAMETERS); | |
2646 var_value.Bind(ChangeUint32ToTagged(value_uint32)); | |
2647 Goto(&allocate_entry_if_needed); | |
2648 } | |
2649 Bind(&int32_values); | |
2650 { | |
2651 Node* value_int32 = LoadFixedTypedArrayElement( | |
2652 data_ptr, index, INT32_ELEMENTS, SMI_PARAMETERS); | |
2653 var_value.Bind(ChangeInt32ToTagged(value_int32)); | |
2654 Goto(&allocate_entry_if_needed); | |
2655 } | |
2656 Bind(&float32_values); | |
2657 { | |
2658 Node* value_float32 = LoadFixedTypedArrayElement( | |
2659 data_ptr, index, FLOAT32_ELEMENTS, SMI_PARAMETERS); | |
2660 var_value.Bind( | |
2661 AllocateHeapNumberWithValue(ChangeFloat32ToFloat64(value_float32))); | |
2662 Goto(&allocate_entry_if_needed); | |
2663 } | |
2664 Bind(&float64_values); | |
2665 { | |
2666 Node* value_float64 = LoadFixedTypedArrayElement( | |
2667 data_ptr, index, FLOAT64_ELEMENTS, SMI_PARAMETERS); | |
2668 var_value.Bind(AllocateHeapNumberWithValue(value_float64)); | |
2669 Goto(&allocate_entry_if_needed); | |
2670 } | |
2671 } | |
2672 } | |
2673 | |
2674 Bind(&set_done); | |
2675 { | |
2676 StoreObjectFieldNoWriteBarrier( | |
2677 iterator, JSArrayIterator::kIteratedObjectOffset, UndefinedConstant()); | |
2678 Goto(&allocate_iterator_result); | |
2679 } | |
2680 | |
2681 Bind(&allocate_key_result); | |
2682 { | |
2683 var_value.Bind(index); | |
2684 var_done.Bind(FalseConstant()); | |
2685 Goto(&allocate_iterator_result); | |
2686 } | |
2687 | |
2688 Bind(&allocate_entry_if_needed); | |
2689 { | |
2690 GotoIf(Int32GreaterThan(instance_type, | |
2691 Int32Constant(LAST_ARRAY_KEY_VALUE_ITERATOR_TYPE)), | |
2692 &allocate_iterator_result); | |
2693 | |
2694 Node* elements = AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); | |
2695 StoreFixedArrayElement(elements, 0, index, SKIP_WRITE_BARRIER); | |
2696 StoreFixedArrayElement(elements, 1, var_value.value(), SKIP_WRITE_BARRIER); | |
2697 | |
2698 Node* entry = Allocate(JSArray::kSize); | |
2699 Node* map = LoadContextElement(LoadNativeContext(context), | |
2700 Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX); | |
2701 | |
2702 StoreMapNoWriteBarrier(entry, map); | |
2703 StoreObjectFieldRoot(entry, JSArray::kPropertiesOffset, | |
2704 Heap::kEmptyFixedArrayRootIndex); | |
2705 StoreObjectFieldNoWriteBarrier(entry, JSArray::kElementsOffset, elements); | |
2706 StoreObjectFieldNoWriteBarrier(entry, JSArray::kLengthOffset, | |
2707 SmiConstant(Smi::FromInt(2))); | |
2708 | |
2709 var_value.Bind(entry); | |
2710 Goto(&allocate_iterator_result); | |
2711 } | |
2712 | |
2713 Bind(&allocate_iterator_result); | |
2714 { | |
2715 Node* result = Allocate(JSIteratorResult::kSize); | |
2716 Node* map = LoadContextElement(LoadNativeContext(context), | |
2717 Context::ITERATOR_RESULT_MAP_INDEX); | |
2718 StoreMapNoWriteBarrier(result, map); | |
2719 StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset, | |
2720 Heap::kEmptyFixedArrayRootIndex); | |
2721 StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset, | |
2722 Heap::kEmptyFixedArrayRootIndex); | |
2723 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, | |
2724 var_value.value()); | |
2725 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset, | |
2726 var_done.value()); | |
2727 Return(result); | |
2728 } | |
2729 | |
2730 Bind(&throw_bad_receiver); | |
2731 { | |
2732 // The {receiver} is not a valid JSArrayIterator. | |
2733 CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context, | |
2734 HeapConstant(operation), iterator); | |
2735 Unreachable(); | |
2736 } | |
2737 | |
2738 Bind(&if_isdetached); | |
2739 { | |
2740 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); | |
2741 CallRuntime(Runtime::kThrowTypeError, context, message, | |
2742 HeapConstant(operation)); | |
2743 Unreachable(); | |
2744 } | |
2745 } | |
2746 | |
2747 } // namespace internal | 1242 } // namespace internal |
2748 } // namespace v8 | 1243 } // namespace v8 |
OLD | NEW |