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

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

Issue 2358263002: [builtins] migrate C++ String Iterator builtins to baseline TurboFan (Closed)
Patch Set: add "break;" statement to switch case Created 4 years, 2 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
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-stub-assembler.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 9
10 namespace v8 { 10 namespace v8 {
(...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 typedef compiler::Node Node; 509 typedef compiler::Node Node;
510 510
511 Node* receiver = assembler->Parameter(0); 511 Node* receiver = assembler->Parameter(0);
512 Node* context = assembler->Parameter(3); 512 Node* context = assembler->Parameter(3);
513 513
514 Node* result = assembler->ToThisValue( 514 Node* result = assembler->ToThisValue(
515 context, receiver, PrimitiveType::kString, "String.prototype.valueOf"); 515 context, receiver, PrimitiveType::kString, "String.prototype.valueOf");
516 assembler->Return(result); 516 assembler->Return(result);
517 } 517 }
518 518
519 BUILTIN(StringPrototypeIterator) { 519 void Builtins::Generate_StringPrototypeIterator(CodeStubAssembler* assembler) {
520 HandleScope scope(isolate); 520 typedef CodeStubAssembler::Label Label;
521 TO_THIS_STRING(object, "String.prototype[Symbol.iterator]"); 521 typedef compiler::Node Node;
522 522 typedef CodeStubAssembler::Variable Variable;
523 Handle<String> string; 523
524 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, 524 Variable var_string(assembler, MachineRepresentation::kTagged);
525 Object::ToString(isolate, object)); 525 Variable var_index(assembler, MachineRepresentation::kTagged);
526 526
527 return *isolate->factory()->NewJSStringIterator(string); 527 Variable* loop_inputs[] = {&var_string, &var_index};
528 Label loop(assembler, 2, loop_inputs);
529 Label allocate_iterator(assembler);
530
531 Node* receiver = assembler->Parameter(0);
532 Node* context = assembler->Parameter(3);
533
534 Node* string = assembler->ToThisString(context, receiver,
535 "String.prototype[Symbol.iterator]");
536 var_string.Bind(string);
537 var_index.Bind(assembler->SmiConstant(Smi::FromInt(0)));
538
539 assembler->Goto(&loop);
540 assembler->Bind(&loop);
541 {
542 // Load the instance type of the {string}.
543 Node* string_instance_type = assembler->LoadInstanceType(string);
Jakob Kummerow 2016/09/29 13:29:49 This is a bug: instead of |string|, you want to us
544
545 // Check if the {string} is a SeqString.
546 Label if_stringisnotsequential(assembler);
547 assembler->Branch(assembler->Word32Equal(
548 assembler->Word32And(string_instance_type,
549 assembler->Int32Constant(
550 kStringRepresentationMask)),
551 assembler->Int32Constant(kSeqStringTag)),
552 &allocate_iterator, &if_stringisnotsequential);
553
554 assembler->Bind(&if_stringisnotsequential);
555 {
556 // Check if the {string} is a ConsString.
557 Label if_stringiscons(assembler), if_stringisnotcons(assembler);
558 assembler->Branch(
559 assembler->Word32Equal(
560 assembler->Word32And(
561 string_instance_type,
562 assembler->Int32Constant(kStringRepresentationMask)),
563 assembler->Int32Constant(kConsStringTag)),
564 &if_stringiscons, &if_stringisnotcons);
565
566 assembler->Bind(&if_stringiscons);
567 {
568 // Flatten cons-string and finish.
569 var_string.Bind(assembler->CallRuntime(
570 Runtime::kFlattenString, assembler->NoContextConstant(), string));
571 assembler->Goto(&allocate_iterator);
572 }
573
574 assembler->Bind(&if_stringisnotcons);
575 {
576 // Check if the {string} is an ExternalString.
577 Label if_stringisnotexternal(assembler);
578 assembler->Branch(
579 assembler->Word32Equal(
580 assembler->Word32And(
581 string_instance_type,
582 assembler->Int32Constant(kStringRepresentationMask)),
583 assembler->Int32Constant(kExternalStringTag)),
584 &allocate_iterator, &if_stringisnotexternal);
585
586 assembler->Bind(&if_stringisnotexternal);
587 {
588 // The {string} is a SlicedString, continue with its parent.
589 Node* index = var_index.value();
590 Node* string_offset =
591 assembler->LoadObjectField(string, SlicedString::kOffsetOffset);
592 Node* string_parent =
593 assembler->LoadObjectField(string, SlicedString::kParentOffset);
594 var_index.Bind(assembler->SmiAdd(index, string_offset));
595 var_string.Bind(string_parent);
596 assembler->Goto(&loop);
597 }
598 }
599 }
600 }
601
602 assembler->Bind(&allocate_iterator);
603 {
604 Node* native_context = assembler->LoadNativeContext(context);
605 Node* map = assembler->LoadFixedArrayElement(
606 native_context,
607 assembler->IntPtrConstant(Context::STRING_ITERATOR_MAP_INDEX), 0,
608 CodeStubAssembler::INTPTR_PARAMETERS);
609 Node* iterator = assembler->Allocate(JSStringIterator::kSize);
610 assembler->StoreMapNoWriteBarrier(iterator, map);
611 assembler->StoreObjectFieldRoot(iterator, JSValue::kPropertiesOffset,
612 Heap::kEmptyFixedArrayRootIndex);
613 assembler->StoreObjectFieldRoot(iterator, JSObject::kElementsOffset,
614 Heap::kEmptyFixedArrayRootIndex);
615 assembler->StoreObjectFieldNoWriteBarrier(
616 iterator, JSStringIterator::kStringOffset, var_string.value());
617
618 assembler->StoreObjectFieldNoWriteBarrier(
619 iterator, JSStringIterator::kNextIndexOffset, var_index.value());
620 assembler->Return(iterator);
621 }
528 } 622 }
529 623
530 BUILTIN(StringIteratorPrototypeNext) { 624 namespace {
531 HandleScope scope(isolate); 625
532 626 // Return the |word32| codepoint at {index}. Supports SeqStrings and
533 if (!args.receiver()->IsJSStringIterator()) { 627 // ExternalStrings.
534 Handle<String> reason = isolate->factory()->NewStringFromAsciiChecked( 628 compiler::Node* LoadSurrogatePairInternal(CodeStubAssembler* assembler,
535 "String Iterator.prototype.next"); 629 compiler::Node* string,
536 THROW_NEW_ERROR_RETURN_FAILURE( 630 compiler::Node* length,
537 isolate, 631 compiler::Node* index,
538 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, reason)); 632 UnicodeEncoding encoding) {
539 } 633 typedef CodeStubAssembler::Label Label;
540 Handle<JSStringIterator> iterator = 634 typedef compiler::Node Node;
541 Handle<JSStringIterator>::cast(args.receiver()); 635 typedef CodeStubAssembler::Variable Variable;
542 Handle<String> string(iterator->string()); 636 Label handle_surrogate_pair(assembler), return_result(assembler);
543 637 Variable var_result(assembler, MachineRepresentation::kWord32);
544 int position = iterator->index(); 638 Variable var_trail(assembler, MachineRepresentation::kWord16);
545 int length = string->length(); 639 var_result.Bind(assembler->Int32Constant(0));
546 640 var_trail.Bind(assembler->Int32Constant(0));
547 if (position < length) { 641
548 uint16_t lead = string->Get(position); 642 Node* string_instance_type = assembler->LoadInstanceType(string);
549 if (lead >= 0xD800 && lead <= 0xDBFF && position + 1 < length) { 643
550 uint16_t trail = string->Get(position + 1); 644 Label if_stringissequential(assembler), if_stringisexternal(assembler);
551 if (V8_LIKELY(trail >= 0xDC00 && trail <= 0xDFFF)) { 645 assembler->Branch(assembler->Word32Equal(
552 // Return surrogate pair code units 646 assembler->Word32And(string_instance_type,
553 iterator->set_index(position + 2); 647 assembler->Int32Constant(
554 Handle<String> value = 648 kStringRepresentationMask)),
555 isolate->factory()->NewSurrogatePairString(lead, trail); 649 assembler->Int32Constant(kSeqStringTag)),
556 return *isolate->factory()->NewJSIteratorResult(value, false); 650 &if_stringissequential, &if_stringisexternal);
557 } 651
558 } 652 assembler->Bind(&if_stringissequential);
559 653 {
560 // Return single code unit 654 Label if_stringisonebyte(assembler), if_stringistwobyte(assembler);
561 iterator->set_index(position + 1); 655 assembler->Branch(
562 Handle<String> value = 656 assembler->Word32Equal(
563 isolate->factory()->LookupSingleCharacterStringFromCode(lead); 657 assembler->Word32And(string_instance_type,
564 return *isolate->factory()->NewJSIteratorResult(value, false); 658 assembler->Int32Constant(kStringEncodingMask)),
565 } 659 assembler->Int32Constant(kOneByteStringTag)),
566 660 &if_stringisonebyte, &if_stringistwobyte);
567 iterator->set_string(isolate->heap()->empty_string()); 661
568 662 assembler->Bind(&if_stringisonebyte);
569 return *isolate->factory()->NewJSIteratorResult( 663 {
570 isolate->factory()->undefined_value(), true); 664 var_result.Bind(assembler->Load(
665 MachineType::Uint8(), string,
666 assembler->IntPtrAdd(
667 index, assembler->IntPtrConstant(SeqOneByteString::kHeaderSize -
668 kHeapObjectTag))));
669 assembler->Goto(&return_result);
670 }
671
672 assembler->Bind(&if_stringistwobyte);
673 {
674 Node* lead = assembler->Load(
675 MachineType::Uint16(), string,
676 assembler->IntPtrAdd(
677 assembler->WordShl(index, assembler->IntPtrConstant(1)),
678 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize -
679 kHeapObjectTag)));
680 var_result.Bind(lead);
681 Node* next_pos = assembler->Int32Add(index, assembler->Int32Constant(1));
682
683 Label if_isdoublecodeunit(assembler);
684 assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length),
685 &return_result);
686 assembler->GotoIf(
687 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)),
688 &return_result);
689 assembler->Branch(
690 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00)),
691 &if_isdoublecodeunit, &return_result);
692
693 assembler->Bind(&if_isdoublecodeunit);
694 {
695 Node* trail = assembler->Load(
696 MachineType::Uint16(), string,
697 assembler->IntPtrAdd(
698 assembler->WordShl(next_pos, assembler->IntPtrConstant(1)),
699 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize -
700 kHeapObjectTag)));
701 assembler->GotoIf(
702 assembler->Uint32LessThan(trail, assembler->Int32Constant(0xDC00)),
703 &return_result);
704 assembler->GotoIf(assembler->Uint32GreaterThanOrEqual(
705 trail, assembler->Int32Constant(0xE000)),
706 &return_result);
707
708 var_trail.Bind(trail);
709 assembler->Goto(&handle_surrogate_pair);
710 }
711 }
712 }
713
714 assembler->Bind(&if_stringisexternal);
715 {
716 assembler->Assert(assembler->Word32Equal(
717 assembler->Word32And(
718 string_instance_type,
719 assembler->Int32Constant(kStringRepresentationMask)),
720 assembler->Int32Constant(kExternalStringTag)));
721 Label if_stringisshort(assembler), if_stringisnotshort(assembler);
722
723 assembler->Branch(assembler->Word32Equal(
724 assembler->Word32And(string_instance_type,
725 assembler->Int32Constant(
726 kShortExternalStringMask)),
727 assembler->Int32Constant(0)),
728 &if_stringisshort, &if_stringisnotshort);
729
730 assembler->Bind(&if_stringisshort);
731 {
732 // Load the actual resource data from the {string}.
733 Node* string_resource_data = assembler->LoadObjectField(
734 string, ExternalString::kResourceDataOffset, MachineType::Pointer());
735
736 Label if_stringistwobyte(assembler), if_stringisonebyte(assembler);
737 assembler->Branch(assembler->Word32Equal(
738 assembler->Word32And(
739 string_instance_type,
740 assembler->Int32Constant(kStringEncodingMask)),
741 assembler->Int32Constant(kTwoByteStringTag)),
742 &if_stringistwobyte, &if_stringisonebyte);
743
744 assembler->Bind(&if_stringisonebyte);
745 {
746 var_result.Bind(
747 assembler->Load(MachineType::Uint8(), string_resource_data, index));
748 assembler->Goto(&return_result);
749 }
750
751 assembler->Bind(&if_stringistwobyte);
752 {
753 Label if_isdoublecodeunit(assembler);
754 Node* lead = assembler->Load(
755 MachineType::Uint16(), string_resource_data,
756 assembler->WordShl(index, assembler->IntPtrConstant(1)));
757 var_result.Bind(lead);
758 Node* next_pos =
759 assembler->Int32Add(index, assembler->Int32Constant(1));
760
761 assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length),
762 &return_result);
763 assembler->GotoIf(
764 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)),
765 &return_result);
766 assembler->Branch(
767 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00)),
768 &if_isdoublecodeunit, &return_result);
769
770 assembler->Bind(&if_isdoublecodeunit);
771 {
772 Node* trail = assembler->Load(
773 MachineType::Uint16(), string,
774 assembler->IntPtrAdd(
775 assembler->WordShl(next_pos, assembler->IntPtrConstant(1)),
776 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize -
777 kHeapObjectTag)));
778 assembler->GotoIf(assembler->Uint32LessThan(
779 trail, assembler->Int32Constant(0xDC00)),
780 &return_result);
781 assembler->GotoIf(assembler->Uint32GreaterThanOrEqual(
782 trail, assembler->Int32Constant(0xE000)),
783 &return_result);
784
785 var_trail.Bind(trail);
786 assembler->Goto(&handle_surrogate_pair);
787 }
788 }
789 }
790
791 assembler->Bind(&if_stringisnotshort);
792 {
793 Label if_isdoublecodeunit(assembler);
794 Node* lead = assembler->SmiToWord32(assembler->CallRuntime(
795 Runtime::kExternalStringGetChar, assembler->NoContextConstant(),
796 string, assembler->SmiTag(index)));
797 var_result.Bind(lead);
798 Node* next_pos = assembler->Int32Add(index, assembler->Int32Constant(1));
799
800 assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length),
801 &return_result);
802 assembler->GotoIf(
803 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)),
804 &return_result);
805 assembler->Branch(assembler->Uint32GreaterThanOrEqual(
806 lead, assembler->Int32Constant(0xDC00)),
807 &return_result, &if_isdoublecodeunit);
808
809 assembler->Bind(&if_isdoublecodeunit);
810 {
811 Node* trail = assembler->SmiToWord32(assembler->CallRuntime(
812 Runtime::kExternalStringGetChar, assembler->NoContextConstant(),
813 string, assembler->SmiTag(next_pos)));
814 assembler->GotoIf(
815 assembler->Uint32LessThan(trail, assembler->Int32Constant(0xDC00)),
816 &return_result);
817 assembler->GotoIf(assembler->Uint32GreaterThanOrEqual(
818 trail, assembler->Int32Constant(0xE000)),
819 &return_result);
820 var_trail.Bind(trail);
821 assembler->Goto(&handle_surrogate_pair);
822 }
823 }
824 }
825
826 assembler->Bind(&handle_surrogate_pair);
827 {
828 Node* lead = var_result.value();
829 Node* trail = var_trail.value();
830 #ifdef ENABLE_SLOW_DCHECKS
831 // Check that this path is only taken if a surrogate pair is found
832 assembler->Assert(assembler->Uint32GreaterThanOrEqual(
833 lead, assembler->Int32Constant(0xD800)));
834 assembler->Assert(
835 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00)));
836 assembler->Assert(assembler->Uint32GreaterThanOrEqual(
837 trail, assembler->Int32Constant(0xDC00)));
838 assembler->Assert(
839 assembler->Uint32LessThan(trail, assembler->Int32Constant(0xE000)));
840 #endif
841
842 switch (encoding) {
843 case UnicodeEncoding::UTF16:
844 var_result.Bind(assembler->WordOr(
845 assembler->WordShl(trail, assembler->Int32Constant(16)), lead));
846 break;
847
848 case UnicodeEncoding::UTF32: {
849 // Convert UTF16 surrogate pair into |word32| code point, encoded as
850 // UTF32.
851 Node* surrogate_offset =
852 assembler->Int32Constant(0x10000 - (0xD800 << 10) - 0xDC00);
853
854 // (lead << 10) + trail + SURROGATE_OFFSET
855 var_result.Bind(assembler->Int32Add(
856 assembler->WordShl(lead, assembler->Int32Constant(10)),
857 assembler->Int32Add(trail, surrogate_offset)));
858 break;
859 }
860 }
861 assembler->Goto(&return_result);
862 }
863
864 assembler->Bind(&return_result);
865 return var_result.value();
571 } 866 }
572 867
868 compiler::Node* LoadSurrogatePairAt(CodeStubAssembler* assembler,
869 compiler::Node* string,
870 compiler::Node* length,
871 compiler::Node* index) {
872 return LoadSurrogatePairInternal(assembler, string, length, index,
873 UnicodeEncoding::UTF16);
874 }
875
876 } // namespace
877
878 void Builtins::Generate_StringIteratorPrototypeNext(
879 CodeStubAssembler* assembler) {
880 typedef CodeStubAssembler::Label Label;
881 typedef compiler::Node Node;
882 typedef CodeStubAssembler::Variable Variable;
883
884 Variable var_value(assembler, MachineRepresentation::kTagged);
885 Variable var_done(assembler, MachineRepresentation::kTagged);
886
887 var_value.Bind(assembler->UndefinedConstant());
888 var_done.Bind(assembler->BooleanConstant(true));
889
890 Label throw_bad_receiver(assembler), next_codepoint(assembler),
891 return_result(assembler);
892
893 Node* iterator = assembler->Parameter(0);
894 Node* context = assembler->Parameter(3);
895
896 assembler->GotoIf(assembler->WordIsSmi(iterator), &throw_bad_receiver);
897 assembler->GotoUnless(
898 assembler->WordEqual(assembler->LoadInstanceType(iterator),
899 assembler->Int32Constant(JS_STRING_ITERATOR_TYPE)),
900 &throw_bad_receiver);
901
902 Node* string =
903 assembler->LoadObjectField(iterator, JSStringIterator::kStringOffset);
904 Node* position =
905 assembler->LoadObjectField(iterator, JSStringIterator::kNextIndexOffset);
906 Node* length = assembler->LoadObjectField(string, String::kLengthOffset);
907
908 assembler->Branch(assembler->SmiLessThan(position, length), &next_codepoint,
909 &return_result);
910
911 assembler->Bind(&next_codepoint);
912 {
913 Node* ch =
914 LoadSurrogatePairAt(assembler, string, assembler->SmiUntag(length),
915 assembler->SmiUntag(position));
916 Node* value = assembler->StringFromCodePoint(ch, UnicodeEncoding::UTF16);
917 var_value.Bind(value);
918 Node* length = assembler->LoadObjectField(value, String::kLengthOffset);
919 assembler->StoreObjectFieldNoWriteBarrier(
920 iterator, JSStringIterator::kNextIndexOffset,
921 assembler->SmiAdd(position, length));
922 var_done.Bind(assembler->BooleanConstant(false));
923 assembler->Goto(&return_result);
924 }
925
926 assembler->Bind(&return_result);
927 {
928 Node* native_context = assembler->LoadNativeContext(context);
929 Node* map = assembler->LoadFixedArrayElement(
930 native_context,
931 assembler->IntPtrConstant(Context::ITERATOR_RESULT_MAP_INDEX), 0,
932 CodeStubAssembler::INTPTR_PARAMETERS);
933 Node* result = assembler->Allocate(JSIteratorResult::kSize);
934 assembler->StoreMapNoWriteBarrier(result, map);
935 assembler->StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset,
936 Heap::kEmptyFixedArrayRootIndex);
937 assembler->StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset,
938 Heap::kEmptyFixedArrayRootIndex);
939 assembler->StoreObjectFieldNoWriteBarrier(
940 result, JSIteratorResult::kValueOffset, var_value.value());
941 assembler->StoreObjectFieldNoWriteBarrier(
942 result, JSIteratorResult::kDoneOffset, var_done.value());
943 assembler->Return(result);
944 }
945
946 assembler->Bind(&throw_bad_receiver);
947 {
948 // The {receiver} is not a valid JSGeneratorObject.
949 Node* result = assembler->CallRuntime(
950 Runtime::kThrowIncompatibleMethodReceiver, context,
951 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked(
952 "String Iterator.prototype.next", TENURED)),
953 iterator);
954 assembler->Return(result); // Never reached.
955 }
956 }
957
573 } // namespace internal 958 } // namespace internal
574 } // namespace v8 959 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-stub-assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698