Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(157)

Side by Side Diff: src/builtins/builtins-array.cc

Issue 2709773002: [builtins] (Re-)implement Array.prototype.every/some with the CSA (Closed)
Patch Set: Add some Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 409 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 420
421 if (JSArray::HasReadOnlyLength(array)) { 421 if (JSArray::HasReadOnlyLength(array)) {
422 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); 422 return CallJsIntrinsic(isolate, isolate->array_unshift(), args);
423 } 423 }
424 424
425 ElementsAccessor* accessor = array->GetElementsAccessor(); 425 ElementsAccessor* accessor = array->GetElementsAccessor();
426 int new_length = accessor->Unshift(array, &args, to_add); 426 int new_length = accessor->Unshift(array, &args, to_add);
427 return Smi::FromInt(new_length); 427 return Smi::FromInt(new_length);
428 } 428 }
429 429
430 class ForEachCodeStubAssembler : public CodeStubAssembler { 430 class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
431 public: 431 public:
432 explicit ForEachCodeStubAssembler(compiler::CodeAssemblerState* state) 432 explicit ArrayBuiltinCodeStubAssembler(compiler::CodeAssemblerState* state)
433 : CodeStubAssembler(state) {} 433 : CodeStubAssembler(state) {}
434 434
435 void VisitOneElement(Node* context, Node* this_arg, Node* o, Node* k, 435 typedef std::function<Node*(Node* o, Node* len)> BuiltinResultGenerator;
436 Node* callbackfn) { 436 typedef std::function<void(Node* a, Node* pK, Node* value)>
437 Comment("begin VisitOneElement"); 437 CallResultProcessor;
438 438
439 // a. Let Pk be ToString(k). 439 void GenerateArrayIteratingBuiltinBody(const char* name, Node* receiver,
440 Node* p_k = ToString(context, k); 440 Node* callbackfn, Node* this_arg,
441 Node* context,
442 BuiltinResultGenerator generator,
Igor Sheludko 2017/03/10 14:14:44 const X&
danno 2017/03/13 07:22:06 Done.
443 CallResultProcessor processor) {
Igor Sheludko 2017/03/10 14:14:45 Same here.
danno 2017/03/13 07:22:06 Done.
444 Variable k(this, MachineRepresentation::kTagged, SmiConstant(0));
445 Label non_array(this), slow(this, &k), array_changes(this, &k);
441 446
442 // b. Let kPresent be HasProperty(O, Pk). 447 // TODO(danno): Seriously? Do we really need to throw the exact error
443 // c. ReturnIfAbrupt(kPresent). 448 // message on null and undefined so that the webkit tests pass?
444 Node* k_present = 449 Label throw_null_undefined_exception(this, Label::kDeferred);
445 CallStub(CodeFactory::HasProperty(isolate()), context, p_k, o); 450 GotoIf(WordEqual(receiver, NullConstant()),
451 &throw_null_undefined_exception);
452 GotoIf(WordEqual(receiver, UndefinedConstant()),
453 &throw_null_undefined_exception);
446 454
447 // d. If kPresent is true, then 455 // By the book: taken directly from the ECMAScript 2015 specification
448 Label not_present(this);
449 GotoIf(WordNotEqual(k_present, TrueConstant()), &not_present);
450 456
451 // i. Let kValue be Get(O, Pk). 457 // 1. Let O be ToObject(this value).
452 // ii. ReturnIfAbrupt(kValue). 458 // 2. ReturnIfAbrupt(O)
453 Node* k_value = 459 Node* o = CallStub(CodeFactory::ToObject(isolate()), context, receiver);
454 CallStub(CodeFactory::GetProperty(isolate()), context, o, k);
455 460
456 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). 461 // 3. Let len be ToLength(Get(O, "length")).
457 // iv. ReturnIfAbrupt(funcResult). 462 // 4. ReturnIfAbrupt(len).
458 CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg, k_value, 463 Variable merged_length(this, MachineRepresentation::kTagged);
459 k, o); 464 Label has_length(this, &merged_length), not_js_array(this);
465 GotoIf(DoesntHaveInstanceType(o, JS_ARRAY_TYPE), &not_js_array);
466 merged_length.Bind(LoadJSArrayLength(o));
467 Goto(&has_length);
468 Bind(&not_js_array);
469 Node* len_property =
470 CallStub(CodeFactory::GetProperty(isolate()), context, o,
471 HeapConstant(isolate()->factory()->length_string()));
472 merged_length.Bind(
473 CallStub(CodeFactory::ToLength(isolate()), context, len_property));
474 Goto(&has_length);
475 Bind(&has_length);
476 Node* len = merged_length.value();
460 477
461 Goto(&not_present); 478 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
462 Bind(&not_present); 479 Label type_exception(this, Label::kDeferred);
463 Comment("end VisitOneElement"); 480 Label done(this);
481 GotoIf(TaggedIsSmi(callbackfn), &type_exception);
482 Branch(IsCallableMap(LoadMap(callbackfn)), &done, &type_exception);
483
484 Bind(&throw_null_undefined_exception);
485 {
486 std::string s("Array.prototype.");
487 s += name;
Igor Sheludko 2017/03/10 14:14:45 name could just be a "Array.prototype.smth" for si
danno 2017/03/13 07:22:06 Unfortunately, these must match the method name ex
Igor Sheludko 2017/03/13 08:21:20 I meant to pass full method name as a parameter in
488 CallRuntime(Runtime::kThrowTypeError, context,
489 SmiConstant(MessageTemplate::kCalledOnNullOrUndefined),
490 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked(
491 s.c_str())));
492 Unreachable();
493 }
494
495 Bind(&type_exception);
496 {
497 CallRuntime(Runtime::kThrowTypeError, context,
498 SmiConstant(MessageTemplate::kCalledNonCallable), callbackfn);
499 Unreachable();
500 }
501
502 Bind(&done);
503
504 Node* a = generator(o, len);
505
506 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
507 // [Already done by the arguments adapter]
508
509 HandleFastElements(context, this_arg, o, len, callbackfn, processor, a, k,
510 &slow);
511
512 // 7. Let k be 0.
513 // Already done above in initialization of the Variable k
514
515 Bind(&slow);
516 {
517 // 8. Repeat, while k < len
518 Label loop(this, &k);
519 Label after_loop(this);
520 Goto(&loop);
521 Bind(&loop);
522 {
523 GotoUnlessNumberLessThan(k.value(), len, &after_loop);
524
525 Label done_element(this);
526 // a. Let Pk be ToString(k).
527 Node* p_k = ToString(context, k.value());
528
529 // b. Let kPresent be HasProperty(O, Pk).
530 // c. ReturnIfAbrupt(kPresent).
531 Node* k_present =
532 CallStub(CodeFactory::HasProperty(isolate()), context, p_k, o);
533
534 // d. If kPresent is true, then
535 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element);
536
537 // i. Let kValue be Get(O, Pk).
538 // ii. ReturnIfAbrupt(kValue).
539 Node* k_value = CallStub(CodeFactory::GetProperty(isolate()), context,
540 o, k.value());
541
542 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»).
543 // iv. ReturnIfAbrupt(funcResult).
544 Node* result = CallJS(CodeFactory::Call(isolate()), context, callbackfn,
545 this_arg, k_value, k.value(), o);
546
547 processor(a, p_k, result);
548 Goto(&done_element);
549 Bind(&done_element);
550
551 // e. Increase k by 1.
552 k.Bind(NumberInc(k.value()));
553 Goto(&loop);
554 }
555 Bind(&after_loop);
556 Return(a);
557 }
464 } 558 }
465 559
466 void VisitAllFastElements(Node* context, ElementsKind kind, Node* this_arg, 560 private:
467 Node* o, Node* len, Node* callbackfn, 561 Node* VisitAllFastElementsOneKind(Node* context, ElementsKind kind,
468 ParameterMode mode) { 562 Node* this_arg, Node* o, Node* len,
469 Comment("begin VisitAllFastElements"); 563 Node* callbackfn,
564 CallResultProcessor processor, Node* a,
Igor Sheludko 2017/03/10 14:14:45 Same here.
danno 2017/03/13 07:22:06 Done.
565 Label* array_changed, ParameterMode mode) {
566 Comment("begin VisitAllFastElementsOneKind");
470 Variable original_map(this, MachineRepresentation::kTagged); 567 Variable original_map(this, MachineRepresentation::kTagged);
471 original_map.Bind(LoadMap(o)); 568 original_map.Bind(LoadMap(o));
472 VariableList list({&original_map}, zone()); 569 VariableList list({&original_map}, zone());
570 Node* last_index = nullptr;
473 BuildFastLoop( 571 BuildFastLoop(
474 list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode), 572 list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode),
475 [context, kind, this, o, &original_map, callbackfn, this_arg, 573 [context, kind, this, o, &original_map, callbackfn, this_arg, processor,
Igor Sheludko 2017/03/10 14:14:44 I think these long capture lists do not contribute
danno 2017/03/13 07:22:06 Done.
476 mode](Node* index) { 574 a, array_changed, &last_index, mode](Node* index) {
477 Label one_element_done(this), array_changed(this, Label::kDeferred), 575 last_index = index;
478 hole_element(this); 576 Label one_element_done(this), hole_element(this);
479 577
480 // Check if o's map has changed during the callback. If so, we have to 578 // Check if o's map has changed during the callback. If so, we have to
481 // fall back to the slower spec implementation for the rest of the 579 // fall back to the slower spec implementation for the rest of the
482 // iteration. 580 // iteration.
483 Node* o_map = LoadMap(o); 581 Node* o_map = LoadMap(o);
484 GotoIf(WordNotEqual(o_map, original_map.value()), &array_changed); 582 GotoIf(WordNotEqual(o_map, original_map.value()), array_changed);
485 583
486 // Check if o's length has changed during the callback and if the 584 // Check if o's length has changed during the callback and if the
487 // index is now out of range of the new length. 585 // index is now out of range of the new length.
488 Node* tagged_index = ParameterToTagged(index, mode); 586 Node* tagged_index = ParameterToTagged(index, mode);
489 GotoIf(SmiGreaterThanOrEqual(tagged_index, LoadJSArrayLength(o)), 587 GotoIf(SmiGreaterThanOrEqual(tagged_index, LoadJSArrayLength(o)),
490 &array_changed); 588 array_changed);
491 589
492 // Re-load the elements array. If may have been resized. 590 // Re-load the elements array. If may have been resized.
493 Node* elements = LoadElements(o); 591 Node* elements = LoadElements(o);
494 592
495 // Fast case: load the element directly from the elements FixedArray 593 // Fast case: load the element directly from the elements FixedArray
496 // and call the callback if the element is not the hole. 594 // and call the callback if the element is not the hole.
497 DCHECK(kind == FAST_ELEMENTS || kind == FAST_DOUBLE_ELEMENTS); 595 DCHECK(kind == FAST_ELEMENTS || kind == FAST_DOUBLE_ELEMENTS);
498 int base_size = kind == FAST_ELEMENTS 596 int base_size = kind == FAST_ELEMENTS
499 ? FixedArray::kHeaderSize 597 ? FixedArray::kHeaderSize
500 : (FixedArray::kHeaderSize - kHeapObjectTag); 598 : (FixedArray::kHeaderSize - kHeapObjectTag);
501 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); 599 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size);
502 Node* value = nullptr; 600 Node* value = nullptr;
503 if (kind == FAST_ELEMENTS) { 601 if (kind == FAST_ELEMENTS) {
504 value = LoadObjectField(elements, offset); 602 value = LoadObjectField(elements, offset);
505 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); 603 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element);
506 } else { 604 } else {
507 Node* double_value = 605 Node* double_value =
508 LoadDoubleWithHoleCheck(elements, offset, &hole_element); 606 LoadDoubleWithHoleCheck(elements, offset, &hole_element);
509 value = AllocateHeapNumberWithValue(double_value); 607 value = AllocateHeapNumberWithValue(double_value);
510 } 608 }
511 CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg, 609 Node* result = CallJS(CodeFactory::Call(isolate()), context,
512 value, tagged_index, o); 610 callbackfn, this_arg, value, tagged_index, o);
611 processor(a, tagged_index, result);
513 Goto(&one_element_done); 612 Goto(&one_element_done);
514 613
515 Bind(&hole_element); 614 Bind(&hole_element);
615 // Check if o's prototype change unexpectedly has elements after the
616 // callback in the case of a hole.
516 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, 617 BranchIfPrototypesHaveNoElements(o_map, &one_element_done,
517 &array_changed); 618 array_changed);
518
519 // O's changed during the forEach. Use the implementation precisely
520 // specified in the spec for the rest of the iteration, also making
521 // the failed original_map sticky in case of a subseuent change that
522 // goes back to the original map.
523 Bind(&array_changed);
524 VisitOneElement(context, this_arg, o, ParameterToTagged(index, mode),
525 callbackfn);
526 original_map.Bind(UndefinedConstant());
527 Goto(&one_element_done);
528 619
529 Bind(&one_element_done); 620 Bind(&one_element_done);
530 }, 621 },
531 1, mode, IndexAdvanceMode::kPost); 622 1, mode, IndexAdvanceMode::kPost);
532 Comment("end VisitAllFastElements"); 623 Comment("end VisitAllFastElementsOneKind");
624 return last_index;
625 }
626
627 void HandleFastElements(Node* context, Node* this_arg, Node* o, Node* len,
628 Node* callbackfn, CallResultProcessor processor,
629 Node* a, Variable& k, Label* slow) {
630 Label switch_on_elements_kind(this), fast_elements(this),
631 maybe_double_elements(this), fast_double_elements(this);
632
633 Comment("begin HandleFastElements");
634 // Non-smi lengths must use the slow path.
635 GotoIf(TaggedIsNotSmi(len), slow);
636
637 BranchIfFastJSArray(o, context,
638 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ,
639 &switch_on_elements_kind, slow);
640
641 Bind(&switch_on_elements_kind);
642 // Select by ElementsKind
643 Node* o_map = LoadMap(o);
644 Node* bit_field2 = LoadMapBitField2(o_map);
645 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
646 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)),
647 &maybe_double_elements, &fast_elements);
648
649 ParameterMode mode = OptimalParameterMode();
650 Bind(&fast_elements);
651 {
652 Label array_changed(this, Label::kDeferred);
653 Node* last_index = VisitAllFastElementsOneKind(
654 context, FAST_ELEMENTS, this_arg, o, len, callbackfn, processor, a,
655 &array_changed, mode);
656
657 // No exception, return success
658 Return(a);
659
660 Bind(&array_changed);
661 k.Bind(ParameterToTagged(last_index, mode));
662 Goto(slow);
663 }
664
665 Bind(&maybe_double_elements);
666 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)),
667 slow, &fast_double_elements);
668
669 Bind(&fast_double_elements);
670 {
671 Label array_changed(this, Label::kDeferred);
672 Node* last_index = VisitAllFastElementsOneKind(
673 context, FAST_DOUBLE_ELEMENTS, this_arg, o, len, callbackfn,
674 processor, a, &array_changed, mode);
675
676 // No exception, return success
677 Return(a);
678
679 Bind(&array_changed);
680 k.Bind(ParameterToTagged(last_index, mode));
681 Goto(slow);
682 }
533 } 683 }
534 }; 684 };
535 685
536 TF_BUILTIN(ArrayForEach, ForEachCodeStubAssembler) { 686 TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) {
537 Label non_array(this), examine_elements(this), fast_elements(this),
538 slow(this), maybe_double_elements(this), fast_double_elements(this);
539
540 Node* receiver = Parameter(ForEachDescriptor::kReceiver); 687 Node* receiver = Parameter(ForEachDescriptor::kReceiver);
541 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); 688 Node* callbackfn = Parameter(ForEachDescriptor::kCallback);
542 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); 689 Node* this_arg = Parameter(ForEachDescriptor::kThisArg);
543 Node* context = Parameter(ForEachDescriptor::kContext); 690 Node* context = Parameter(ForEachDescriptor::kContext);
544 691
545 // TODO(danno): Seriously? Do we really need to throw the exact error message 692 GenerateArrayIteratingBuiltinBody(
546 // on null and undefined so that the webkit tests pass? 693 "forEach", receiver, callbackfn, this_arg, context,
547 Label throw_null_undefined_exception(this, Label::kDeferred); 694 [this](Node*, Node*) { return UndefinedConstant(); },
Igor Sheludko 2017/03/10 14:14:44 [=]
danno 2017/03/13 07:22:06 Done.
548 GotoIf(WordEqual(receiver, NullConstant()), &throw_null_undefined_exception); 695 [](Node* a, Node* p_k, Node* value) {});
549 GotoIf(WordEqual(receiver, UndefinedConstant()), 696 }
550 &throw_null_undefined_exception);
551 697
552 // By the book: taken directly from the ECMAScript 2015 specification 698 TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) {
699 Node* receiver = Parameter(ForEachDescriptor::kReceiver);
700 Node* callbackfn = Parameter(ForEachDescriptor::kCallback);
701 Node* this_arg = Parameter(ForEachDescriptor::kThisArg);
702 Node* context = Parameter(ForEachDescriptor::kContext);
553 703
554 // 1. Let O be ToObject(this value). 704 GenerateArrayIteratingBuiltinBody(
555 // 2. ReturnIfAbrupt(O) 705 "every", receiver, callbackfn, this_arg, context,
556 Node* o = CallStub(CodeFactory::ToObject(isolate()), context, receiver); 706 [this](Node*, Node*) { return TrueConstant(); },
Igor Sheludko 2017/03/10 14:14:44 [=]
danno 2017/03/13 07:22:06 Done.
707 [this](Node* a, Node* p_k, Node* value) {
Igor Sheludko 2017/03/10 14:14:44 Same here.
danno 2017/03/13 07:22:06 Done.
708 Label true_continue(this), return_false(this);
709 BranchIfToBooleanIsTrue(value, &true_continue, &return_false);
710 Bind(&return_false);
711 Return(FalseConstant());
712 Bind(&true_continue);
713 });
714 }
557 715
558 // 3. Let len be ToLength(Get(O, "length")). 716 TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) {
559 // 4. ReturnIfAbrupt(len). 717 Node* receiver = Parameter(ForEachDescriptor::kReceiver);
560 Variable merged_length(this, MachineRepresentation::kTagged); 718 Node* callbackfn = Parameter(ForEachDescriptor::kCallback);
561 Label has_length(this, &merged_length), not_js_array(this); 719 Node* this_arg = Parameter(ForEachDescriptor::kThisArg);
562 GotoIf(DoesntHaveInstanceType(o, JS_ARRAY_TYPE), &not_js_array); 720 Node* context = Parameter(ForEachDescriptor::kContext);
563 merged_length.Bind(LoadJSArrayLength(o));
564 Goto(&has_length);
565 Bind(&not_js_array);
566 Node* len_property =
567 CallStub(CodeFactory::GetProperty(isolate()), context, o,
568 HeapConstant(isolate()->factory()->length_string()));
569 merged_length.Bind(
570 CallStub(CodeFactory::ToLength(isolate()), context, len_property));
571 Goto(&has_length);
572 Bind(&has_length);
573 Node* len = merged_length.value();
574 721
575 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. 722 GenerateArrayIteratingBuiltinBody(
576 Label type_exception(this, Label::kDeferred); 723 "some", receiver, callbackfn, this_arg, context,
577 GotoIf(TaggedIsSmi(callbackfn), &type_exception); 724 [this](Node*, Node*) { return FalseConstant(); },
Igor Sheludko 2017/03/10 14:14:44 [=]
danno 2017/03/13 07:22:06 Done.
578 GotoIfNot(IsCallableMap(LoadMap(callbackfn)), &type_exception); 725 [this](Node* a, Node* p_k, Node* value) {
Igor Sheludko 2017/03/10 14:14:44 Same here.
danno 2017/03/13 07:22:06 Done.
579 726 Label false_continue(this), return_true(this);
580 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. 727 BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
581 // [Already done by the arguments adapter] 728 Bind(&return_true);
582 729 Return(TrueConstant());
583 // Non-smi lengths must use the slow path. 730 Bind(&false_continue);
584 GotoIf(TaggedIsNotSmi(len), &slow); 731 });
585
586 BranchIfFastJSArray(o, context,
587 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ,
588 &examine_elements, &slow);
589
590 Bind(&examine_elements);
591
592 ParameterMode mode = OptimalParameterMode();
593
594 // Select by ElementsKind
595 Node* o_map = LoadMap(o);
596 Node* bit_field2 = LoadMapBitField2(o_map);
597 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
598 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)),
599 &maybe_double_elements, &fast_elements);
600
601 Bind(&fast_elements);
602 {
603 VisitAllFastElements(context, FAST_ELEMENTS, this_arg, o, len, callbackfn,
604 mode);
605
606 // No exception, return success
607 Return(UndefinedConstant());
608 }
609
610 Bind(&maybe_double_elements);
611 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)),
612 &slow, &fast_double_elements);
613
614 Bind(&fast_double_elements);
615 {
616 VisitAllFastElements(context, FAST_DOUBLE_ELEMENTS, this_arg, o, len,
617 callbackfn, mode);
618
619 // No exception, return success
620 Return(UndefinedConstant());
621 }
622
623 Bind(&slow);
624 {
625 // By the book: taken from the ECMAScript 2015 specification (cont.)
626
627 // 7. Let k be 0.
628 Variable k(this, MachineRepresentation::kTagged);
629 k.Bind(SmiConstant(0));
630
631 // 8. Repeat, while k < len
632 Label loop(this, &k);
633 Label after_loop(this);
634 Goto(&loop);
635 Bind(&loop);
636 {
637 GotoUnlessNumberLessThan(k.value(), len, &after_loop);
638
639 VisitOneElement(context, this_arg, o, k.value(), callbackfn);
640
641 // e. Increase k by 1.
642 k.Bind(NumberInc(k.value()));
643 Goto(&loop);
644 }
645 Bind(&after_loop);
646 Return(UndefinedConstant());
647 }
648
649 Bind(&throw_null_undefined_exception);
650 {
651 CallRuntime(Runtime::kThrowTypeError, context,
652 SmiConstant(MessageTemplate::kCalledOnNullOrUndefined),
653 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked(
654 "Array.prototype.forEach")));
655 Unreachable();
656 }
657
658 Bind(&type_exception);
659 {
660 CallRuntime(Runtime::kThrowTypeError, context,
661 SmiConstant(MessageTemplate::kCalledNonCallable), callbackfn);
662 Unreachable();
663 }
664 } 732 }
665 733
666 BUILTIN(ArraySlice) { 734 BUILTIN(ArraySlice) {
667 HandleScope scope(isolate); 735 HandleScope scope(isolate);
668 Handle<Object> receiver = args.receiver(); 736 Handle<Object> receiver = args.receiver();
669 int len = -1; 737 int len = -1;
670 int relative_start = 0; 738 int relative_start = 0;
671 int relative_end = 0; 739 int relative_end = 0;
672 740
673 if (receiver->IsJSArray()) { 741 if (receiver->IsJSArray()) {
(...skipping 2171 matching lines...) Expand 10 before | Expand all | Expand 10 after
2845 { 2913 {
2846 Node* message = assembler.SmiConstant(MessageTemplate::kDetachedOperation); 2914 Node* message = assembler.SmiConstant(MessageTemplate::kDetachedOperation);
2847 assembler.CallRuntime(Runtime::kThrowTypeError, context, message, 2915 assembler.CallRuntime(Runtime::kThrowTypeError, context, message,
2848 assembler.HeapConstant(operation)); 2916 assembler.HeapConstant(operation));
2849 assembler.Unreachable(); 2917 assembler.Unreachable();
2850 } 2918 }
2851 } 2919 }
2852 2920
2853 } // namespace internal 2921 } // namespace internal
2854 } // namespace v8 2922 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-stub-assembler.cc » ('j') | src/code-stub-assembler.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698