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 | 9 |
10 namespace v8 { | 10 namespace v8 { |
(...skipping 598 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
609 typedef compiler::Node Node; | 609 typedef compiler::Node Node; |
610 | 610 |
611 Node* receiver = assembler->Parameter(0); | 611 Node* receiver = assembler->Parameter(0); |
612 Node* context = assembler->Parameter(3); | 612 Node* context = assembler->Parameter(3); |
613 | 613 |
614 Node* result = assembler->ToThisValue( | 614 Node* result = assembler->ToThisValue( |
615 context, receiver, PrimitiveType::kString, "String.prototype.valueOf"); | 615 context, receiver, PrimitiveType::kString, "String.prototype.valueOf"); |
616 assembler->Return(result); | 616 assembler->Return(result); |
617 } | 617 } |
618 | 618 |
619 BUILTIN(StringPrototypeIterator) { | 619 void Builtins::Generate_StringPrototypeIterator(CodeStubAssembler* assembler) { |
620 HandleScope scope(isolate); | 620 typedef CodeStubAssembler::Label Label; |
621 TO_THIS_STRING(object, "String.prototype[Symbol.iterator]"); | 621 typedef compiler::Node Node; |
622 | 622 typedef CodeStubAssembler::Variable Variable; |
623 Handle<String> string; | 623 |
624 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, | 624 Variable var_string(assembler, MachineRepresentation::kTagged); |
625 Object::ToString(isolate, object)); | 625 Variable var_index(assembler, MachineRepresentation::kWord32); |
626 | 626 |
627 return *isolate->factory()->NewJSStringIterator(string); | 627 Variable* loop_inputs[] = {&var_string, &var_index}; |
628 } | 628 Label loop(assembler, 2, loop_inputs); |
629 | 629 Label allocate_iterator(assembler); |
630 BUILTIN(StringIteratorPrototypeNext) { | 630 |
631 HandleScope scope(isolate); | 631 Node* receiver = assembler->Parameter(0); |
632 | 632 Node* context = assembler->Parameter(3); |
633 if (!args.receiver()->IsJSStringIterator()) { | 633 |
634 Handle<String> reason = isolate->factory()->NewStringFromAsciiChecked( | 634 Node* string = assembler->ToThisString(context, receiver, |
635 "String Iterator.prototype.next"); | 635 "String.prototype[Symbol.iterator]"); |
636 THROW_NEW_ERROR_RETURN_FAILURE( | 636 var_string.Bind(string); |
637 isolate, | 637 var_index.Bind(assembler->Int32Constant(0)); |
638 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, reason)); | 638 |
639 } | 639 assembler->Goto(&loop); |
640 Handle<JSStringIterator> iterator = | 640 assembler->Bind(&loop); |
641 Handle<JSStringIterator>::cast(args.receiver()); | 641 { |
642 Handle<String> string(iterator->string()); | 642 // Load the instance type of the {string}. |
643 | 643 Node* string_instance_type = assembler->LoadInstanceType(string); |
644 int position = iterator->index(); | 644 |
645 int length = string->length(); | 645 // Check if the {string} is a SeqString. |
646 | 646 Label if_stringisnotsequential(assembler); |
647 if (position < length) { | 647 assembler->Branch(assembler->Word32Equal( |
648 uint16_t lead = string->Get(position); | 648 assembler->Word32And(string_instance_type, |
649 if (lead >= 0xD800 && lead <= 0xDBFF && position + 1 < length) { | 649 assembler->Int32Constant( |
650 uint16_t trail = string->Get(position + 1); | 650 kStringRepresentationMask)), |
651 if (V8_LIKELY(trail >= 0xDC00 && trail <= 0xDFFF)) { | 651 assembler->Int32Constant(kSeqStringTag)), |
652 // Return surrogate pair code units | 652 &allocate_iterator, &if_stringisnotsequential); |
653 iterator->set_index(position + 2); | 653 |
654 Handle<String> value = | 654 assembler->Bind(&if_stringisnotsequential); |
655 isolate->factory()->NewSurrogatePairString(lead, trail); | 655 { |
656 return *isolate->factory()->NewJSIteratorResult(value, false); | 656 // Check if the {string} is a ConsString. |
657 } | 657 Label if_stringiscons(assembler), if_stringisnotcons(assembler); |
658 } | 658 assembler->Branch( |
659 | 659 assembler->Word32Equal( |
660 // Return single code unit | 660 assembler->Word32And( |
661 iterator->set_index(position + 1); | 661 string_instance_type, |
662 Handle<String> value = | 662 assembler->Int32Constant(kStringRepresentationMask)), |
663 isolate->factory()->LookupSingleCharacterStringFromCode(lead); | 663 assembler->Int32Constant(kConsStringTag)), |
664 return *isolate->factory()->NewJSIteratorResult(value, false); | 664 &if_stringiscons, &if_stringisnotcons); |
665 } | 665 |
666 | 666 assembler->Bind(&if_stringiscons); |
667 iterator->set_string(isolate->heap()->empty_string()); | 667 { |
668 | 668 // Flatten cons-string and finish. |
669 return *isolate->factory()->NewJSIteratorResult( | 669 var_string.Bind(assembler->CallRuntime( |
670 isolate->factory()->undefined_value(), true); | 670 Runtime::kFlattenString, assembler->NoContextConstant(), string)); |
671 assembler->Goto(&allocate_iterator); | |
672 } | |
673 | |
674 assembler->Bind(&if_stringisnotcons); | |
675 { | |
676 // Check if the {string} is an ExternalString. | |
677 Label if_stringisnotexternal(assembler); | |
678 assembler->Branch( | |
679 assembler->Word32Equal( | |
680 assembler->Word32And( | |
681 string_instance_type, | |
682 assembler->Int32Constant(kStringRepresentationMask)), | |
683 assembler->Int32Constant(kExternalStringTag)), | |
684 &allocate_iterator, &if_stringisnotexternal); | |
685 | |
686 assembler->Bind(&if_stringisnotexternal); | |
687 { | |
688 // The {string} is a SlicedString, continue with its parent. | |
689 Node* index = var_index.value(); | |
690 Node* string_offset = assembler->LoadAndUntagObjectField( | |
691 string, SlicedString::kOffsetOffset); | |
692 Node* string_parent = | |
693 assembler->LoadObjectField(string, SlicedString::kParentOffset); | |
694 var_index.Bind(assembler->IntPtrAdd(index, string_offset)); | |
695 var_string.Bind(string_parent); | |
696 assembler->Goto(&loop); | |
697 } | |
698 } | |
699 } | |
700 } | |
701 | |
702 assembler->Bind(&allocate_iterator); | |
703 { | |
704 Node* native_context = assembler->LoadNativeContext(context); | |
705 Node* map = assembler->LoadFixedArrayElement( | |
706 native_context, | |
707 assembler->IntPtrConstant(Context::STRING_ITERATOR_MAP_INDEX), 0, | |
708 CodeStubAssembler::INTPTR_PARAMETERS); | |
709 Node* iterator = assembler->Allocate(JSStringIterator::kSize); | |
710 assembler->StoreMapNoWriteBarrier(iterator, map); | |
711 assembler->StoreObjectFieldRoot(iterator, JSValue::kPropertiesOffset, | |
712 Heap::kEmptyFixedArrayRootIndex); | |
713 assembler->StoreObjectFieldRoot(iterator, JSObject::kElementsOffset, | |
714 Heap::kEmptyFixedArrayRootIndex); | |
715 assembler->StoreObjectFieldNoWriteBarrier( | |
716 iterator, JSStringIterator::kStringOffset, var_string.value()); | |
717 | |
718 assembler->StoreObjectFieldNoWriteBarrier( | |
719 iterator, JSStringIterator::kNextIndexOffset, | |
720 assembler->SmiFromWord32(var_index.value())); | |
721 assembler->Return(iterator); | |
722 } | |
723 } | |
724 | |
725 namespace { | |
726 | |
727 enum class UnicodeEncoding { | |
728 UTF16, // high 16bits trail surrogate, low 16bits lead surrogate | |
729 UTF32 | |
730 }; | |
731 | |
732 // Return the |String| containing a single {codepoint}, which may be encoded | |
733 // as one of the following: a single UTF16 code unit, a |word32| with the | |
734 // high 16 bits set to the trailing surrogate, and low 16 bits set to the lead | |
735 // surrogate, or a single UTF32-encoded codepoint. | |
736 compiler::Node* CreateStringFromCodePointInternal(CodeStubAssembler* assembler, | |
Benedikt Meurer
2016/09/26 04:15:40
Please move this to the CodeStubAssembler as Strin
| |
737 compiler::Node* codepoint, | |
738 UnicodeEncoding encoding) { | |
739 typedef CodeStubAssembler::Label Label; | |
740 typedef compiler::Node Node; | |
741 typedef CodeStubAssembler::Variable Variable; | |
742 | |
743 Variable var_result(assembler, MachineRepresentation::kTagged); | |
744 var_result.Bind(assembler->EmptyStringConstant()); | |
745 | |
746 Label if_isonebyte(assembler), if_istwobyte(assembler), | |
747 return_result(assembler); | |
748 | |
749 assembler->Branch( | |
Benedikt Meurer
2016/09/26 04:15:40
Please restructure this a bit and reuse the existi
caitp
2016/09/26 14:33:54
Done.
| |
750 assembler->Uint32LessThan(codepoint, assembler->Int32Constant(0x100)), | |
751 &if_isonebyte, &if_istwobyte); | |
752 | |
753 assembler->Bind(&if_isonebyte); | |
754 { | |
755 Node* value = assembler->AllocateSeqOneByteString(1); | |
756 assembler->StoreNoWriteBarrier( | |
757 MachineRepresentation::kWord8, value, | |
758 assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - | |
759 kHeapObjectTag), | |
760 codepoint); | |
761 var_result.Bind(value); | |
762 assembler->Goto(&return_result); | |
763 } | |
764 | |
765 assembler->Bind(&if_istwobyte); | |
766 { | |
767 Label if_isdouble(assembler), if_issingle(assembler); | |
768 assembler->Branch( | |
769 assembler->Uint32LessThan(codepoint, assembler->Int32Constant(0x10000)), | |
770 &if_issingle, &if_isdouble); | |
771 | |
772 assembler->Bind(&if_issingle); | |
773 { | |
774 Node* value = assembler->AllocateSeqTwoByteString(1); | |
775 assembler->StoreNoWriteBarrier( | |
776 MachineRepresentation::kWord16, value, | |
777 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
778 kHeapObjectTag), | |
779 codepoint); | |
780 var_result.Bind(value); | |
781 assembler->Goto(&return_result); | |
782 } | |
783 | |
784 assembler->Bind(&if_isdouble); | |
785 { | |
786 switch (encoding) { | |
787 case UnicodeEncoding::UTF16: | |
788 break; | |
789 case UnicodeEncoding::UTF32: { | |
790 // Convert UTF32 to UTF16 code units, and store as a 32 bit word. | |
791 Node* lead_offset = | |
792 assembler->Int32Constant(0xD800 - (0x10000 >> 10)); | |
793 | |
794 Node* lead = assembler->Int32Add( | |
795 assembler->WordShr(codepoint, assembler->Int32Constant(10)), | |
796 lead_offset); | |
797 | |
798 Node* trail = assembler->Int32Add( | |
799 assembler->Word32And(codepoint, assembler->Int32Constant(0x3FF)), | |
800 assembler->Int32Constant(0xDC00)); | |
801 | |
802 codepoint = assembler->Word32Or( | |
803 assembler->WordShl(trail, assembler->Int32Constant(16)), lead); | |
804 } | |
805 default: | |
806 UNREACHABLE(); | |
807 } | |
808 | |
809 Node* value = assembler->AllocateSeqTwoByteString(2); | |
810 assembler->StoreNoWriteBarrier( | |
811 MachineRepresentation::kWord32, value, | |
812 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
813 kHeapObjectTag), | |
814 codepoint); | |
815 var_result.Bind(value); | |
816 assembler->Goto(&return_result); | |
817 } | |
818 } | |
819 | |
820 assembler->Bind(&return_result); | |
821 return var_result.value(); | |
822 } | |
823 | |
824 compiler::Node* CreateStringFromSurrogatePair(CodeStubAssembler* assembler, | |
825 compiler::Node* code_units) { | |
826 return CreateStringFromCodePointInternal(assembler, code_units, | |
827 UnicodeEncoding::UTF16); | |
828 } | |
829 | |
830 // Return the |word32| codepoint at {index}. Supports SeqStrings and | |
831 // ExternalStrings. | |
832 compiler::Node* LoadSurrogatePairInternal(CodeStubAssembler* assembler, | |
833 compiler::Node* string, | |
834 compiler::Node* length, | |
835 compiler::Node* index, | |
836 UnicodeEncoding encoding) { | |
837 typedef CodeStubAssembler::Label Label; | |
838 typedef compiler::Node Node; | |
839 typedef CodeStubAssembler::Variable Variable; | |
840 Label handle_surrogate_pair(assembler), return_result(assembler); | |
841 Variable var_result(assembler, MachineRepresentation::kWord32); | |
842 Variable var_trail(assembler, MachineRepresentation::kWord16); | |
843 var_result.Bind(assembler->Int32Constant(0)); | |
844 var_trail.Bind(assembler->Int32Constant(0)); | |
845 | |
846 Node* string_instance_type = assembler->LoadInstanceType(string); | |
847 | |
848 Label if_stringissequential(assembler), if_stringisexternal(assembler); | |
849 assembler->Branch(assembler->Word32Equal( | |
850 assembler->Word32And(string_instance_type, | |
851 assembler->Int32Constant( | |
852 kStringRepresentationMask)), | |
853 assembler->Int32Constant(kSeqStringTag)), | |
854 &if_stringissequential, &if_stringisexternal); | |
855 | |
856 assembler->Bind(&if_stringissequential); | |
857 { | |
858 Label if_stringisonebyte(assembler), if_stringistwobyte(assembler); | |
859 assembler->Branch( | |
860 assembler->Word32Equal( | |
861 assembler->Word32And(string_instance_type, | |
862 assembler->Int32Constant(kStringEncodingMask)), | |
863 assembler->Int32Constant(kOneByteStringTag)), | |
864 &if_stringisonebyte, &if_stringistwobyte); | |
865 | |
866 assembler->Bind(&if_stringisonebyte); | |
867 { | |
868 var_result.Bind(assembler->Load( | |
869 MachineType::Uint8(), string, | |
870 assembler->IntPtrAdd( | |
871 index, assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - | |
872 kHeapObjectTag)))); | |
873 assembler->Goto(&return_result); | |
874 } | |
875 | |
876 assembler->Bind(&if_stringistwobyte); | |
877 { | |
878 Node* lead = assembler->Load( | |
879 MachineType::Uint16(), string, | |
880 assembler->IntPtrAdd( | |
881 assembler->WordShl(index, assembler->IntPtrConstant(1)), | |
882 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
883 kHeapObjectTag))); | |
884 var_result.Bind(lead); | |
885 Node* next_pos = assembler->Int32Add(index, assembler->Int32Constant(1)); | |
886 | |
887 Label if_isdoublecodeunit(assembler); | |
888 assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length), | |
889 &return_result); | |
890 assembler->GotoIf( | |
891 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)), | |
892 &return_result); | |
893 assembler->Branch( | |
894 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00)), | |
895 &if_isdoublecodeunit, &return_result); | |
896 | |
897 assembler->Bind(&if_isdoublecodeunit); | |
898 { | |
899 Node* trail = assembler->Load( | |
900 MachineType::Uint16(), string, | |
901 assembler->IntPtrAdd( | |
902 assembler->WordShl(next_pos, assembler->IntPtrConstant(1)), | |
903 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
904 kHeapObjectTag))); | |
905 assembler->GotoIf( | |
906 assembler->Uint32LessThan(trail, assembler->Int32Constant(0xDC00)), | |
907 &return_result); | |
908 assembler->GotoIf(assembler->Uint32GreaterThanOrEqual( | |
909 trail, assembler->Int32Constant(0xE000)), | |
910 &return_result); | |
911 | |
912 var_trail.Bind(trail); | |
913 assembler->Goto(&handle_surrogate_pair); | |
914 } | |
915 } | |
916 } | |
917 | |
918 assembler->Bind(&if_stringisexternal); | |
919 { | |
920 assembler->Assert(assembler->Word32Equal( | |
921 assembler->Word32And( | |
922 string_instance_type, | |
923 assembler->Int32Constant(kStringRepresentationMask)), | |
924 assembler->Int32Constant(kExternalStringTag))); | |
925 Label if_stringisshort(assembler), if_stringisnotshort(assembler); | |
926 | |
927 assembler->Branch(assembler->Word32Equal( | |
928 assembler->Word32And(string_instance_type, | |
929 assembler->Int32Constant( | |
930 kShortExternalStringMask)), | |
931 assembler->Int32Constant(0)), | |
932 &if_stringisshort, &if_stringisnotshort); | |
933 | |
934 assembler->Bind(&if_stringisshort); | |
935 { | |
936 // Load the actual resource data from the {string}. | |
937 Node* string_resource_data = assembler->LoadObjectField( | |
938 string, ExternalString::kResourceDataOffset, MachineType::Pointer()); | |
939 | |
940 Label if_stringistwobyte(assembler), if_stringisonebyte(assembler); | |
941 assembler->Branch(assembler->Word32Equal( | |
942 assembler->Word32And( | |
943 string_instance_type, | |
944 assembler->Int32Constant(kStringEncodingMask)), | |
945 assembler->Int32Constant(kTwoByteStringTag)), | |
946 &if_stringistwobyte, &if_stringisonebyte); | |
947 | |
948 assembler->Bind(&if_stringisonebyte); | |
949 { | |
950 var_result.Bind( | |
951 assembler->Load(MachineType::Uint8(), string_resource_data, index)); | |
952 assembler->Goto(&return_result); | |
953 } | |
954 | |
955 assembler->Bind(&if_stringistwobyte); | |
956 { | |
957 Label if_isdoublecodeunit(assembler); | |
958 Node* lead = assembler->Load( | |
959 MachineType::Uint16(), string_resource_data, | |
960 assembler->WordShl(index, assembler->IntPtrConstant(1))); | |
961 var_result.Bind(lead); | |
962 Node* next_pos = | |
963 assembler->Int32Add(index, assembler->Int32Constant(1)); | |
964 | |
965 assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length), | |
966 &return_result); | |
967 assembler->GotoIf( | |
968 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)), | |
969 &return_result); | |
970 assembler->Branch( | |
971 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00)), | |
972 &if_isdoublecodeunit, &return_result); | |
973 | |
974 assembler->Bind(&if_isdoublecodeunit); | |
975 { | |
976 Node* trail = assembler->Load( | |
977 MachineType::Uint16(), string, | |
978 assembler->IntPtrAdd( | |
979 assembler->WordShl(next_pos, assembler->IntPtrConstant(1)), | |
980 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
981 kHeapObjectTag))); | |
982 assembler->GotoIf(assembler->Uint32LessThan( | |
983 trail, assembler->Int32Constant(0xDC00)), | |
984 &return_result); | |
985 assembler->GotoIf(assembler->Uint32GreaterThanOrEqual( | |
986 trail, assembler->Int32Constant(0xE000)), | |
987 &return_result); | |
988 | |
989 var_trail.Bind(trail); | |
990 assembler->Goto(&handle_surrogate_pair); | |
991 } | |
992 } | |
993 } | |
994 | |
995 assembler->Bind(&if_stringisnotshort); | |
996 { | |
997 Label if_isdoublecodeunit(assembler); | |
998 Node* lead = assembler->SmiToWord32(assembler->CallRuntime( | |
999 Runtime::kExternalStringGetChar, assembler->NoContextConstant(), | |
1000 string, assembler->SmiTag(index))); | |
1001 var_result.Bind(lead); | |
1002 Node* next_pos = assembler->Int32Add(index, assembler->Int32Constant(1)); | |
1003 | |
1004 assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length), | |
1005 &return_result); | |
1006 assembler->GotoIf( | |
1007 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)), | |
1008 &return_result); | |
1009 assembler->Branch(assembler->Uint32GreaterThanOrEqual( | |
1010 lead, assembler->Int32Constant(0xDC00)), | |
1011 &return_result, &if_isdoublecodeunit); | |
1012 | |
1013 assembler->Bind(&if_isdoublecodeunit); | |
1014 { | |
1015 Node* trail = assembler->SmiToWord32(assembler->CallRuntime( | |
1016 Runtime::kExternalStringGetChar, assembler->NoContextConstant(), | |
1017 string, assembler->SmiTag(next_pos))); | |
1018 assembler->GotoIf( | |
1019 assembler->Uint32LessThan(trail, assembler->Int32Constant(0xDC00)), | |
1020 &return_result); | |
1021 assembler->GotoIf(assembler->Uint32GreaterThanOrEqual( | |
1022 trail, assembler->Int32Constant(0xE000)), | |
1023 &return_result); | |
1024 var_trail.Bind(trail); | |
1025 assembler->Goto(&handle_surrogate_pair); | |
1026 } | |
1027 } | |
1028 } | |
1029 | |
1030 assembler->Bind(&handle_surrogate_pair); | |
1031 { | |
1032 Node* lead = var_result.value(); | |
1033 Node* trail = var_trail.value(); | |
1034 #ifdef ENABLE_SLOW_DCHECKS | |
1035 // Check that this path is only taken if a surrogate pair is found | |
1036 assembler->Assert(assembler->Uint32GreaterThanOrEqual( | |
1037 lead, assembler->Int32Constant(0xD800))); | |
1038 assembler->Assert( | |
1039 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00))); | |
1040 assembler->Assert(assembler->Uint32GreaterThanOrEqual( | |
1041 trail, assembler->Int32Constant(0xDC00))); | |
1042 assembler->Assert( | |
1043 assembler->Uint32LessThan(trail, assembler->Int32Constant(0xE000))); | |
1044 #endif | |
1045 | |
1046 switch (encoding) { | |
1047 case UnicodeEncoding::UTF16: | |
1048 var_result.Bind(assembler->WordOr( | |
1049 assembler->WordShl(trail, assembler->Int32Constant(16)), lead)); | |
1050 break; | |
1051 | |
1052 case UnicodeEncoding::UTF32: { | |
1053 // Convert UTF16 surrogate pair into |word32| code point, encoded as | |
1054 // UTF32. | |
1055 Node* surrogate_offset = | |
1056 assembler->Int32Constant(0x10000 - (0xD800 << 10) - 0xDC00); | |
1057 | |
1058 // (lead << 10) + trail + SURROGATE_OFFSET | |
1059 var_result.Bind(assembler->Int32Add( | |
1060 assembler->WordShl(lead, assembler->Int32Constant(10)), | |
1061 assembler->Int32Add(trail, surrogate_offset))); | |
1062 break; | |
1063 } | |
1064 } | |
1065 assembler->Goto(&return_result); | |
1066 } | |
1067 | |
1068 assembler->Bind(&return_result); | |
1069 return var_result.value(); | |
1070 } | |
1071 | |
1072 compiler::Node* LoadSurrogatePairAt(CodeStubAssembler* assembler, | |
1073 compiler::Node* string, | |
1074 compiler::Node* length, | |
1075 compiler::Node* index) { | |
1076 return LoadSurrogatePairInternal(assembler, string, length, index, | |
1077 UnicodeEncoding::UTF16); | |
1078 } | |
1079 | |
1080 } // namespace | |
1081 | |
1082 void Builtins::Generate_StringIteratorPrototypeNext( | |
1083 CodeStubAssembler* assembler) { | |
1084 typedef CodeStubAssembler::Label Label; | |
1085 typedef compiler::Node Node; | |
1086 typedef CodeStubAssembler::Variable Variable; | |
1087 | |
1088 Variable var_value(assembler, MachineRepresentation::kTagged); | |
1089 Variable var_done(assembler, MachineRepresentation::kTagged); | |
1090 | |
1091 var_value.Bind(assembler->UndefinedConstant()); | |
1092 var_done.Bind(assembler->BooleanConstant(true)); | |
1093 | |
1094 Label throw_bad_receiver(assembler), next_codepoint(assembler), | |
1095 return_result(assembler); | |
1096 | |
1097 Node* iterator = assembler->Parameter(0); | |
1098 Node* context = assembler->Parameter(3); | |
1099 | |
1100 assembler->GotoIf(assembler->WordIsSmi(iterator), &throw_bad_receiver); | |
1101 assembler->GotoUnless( | |
1102 assembler->WordEqual(assembler->LoadInstanceType(iterator), | |
1103 assembler->Int32Constant(JS_STRING_ITERATOR_TYPE)), | |
1104 &throw_bad_receiver); | |
1105 | |
1106 Node* string = | |
1107 assembler->LoadObjectField(iterator, JSStringIterator::kStringOffset); | |
1108 Node* position = assembler->LoadAndUntagObjectField( | |
1109 iterator, JSStringIterator::kNextIndexOffset); | |
1110 Node* length = | |
1111 assembler->LoadAndUntagObjectField(string, String::kLengthOffset); | |
1112 | |
1113 assembler->Branch(assembler->Int32LessThan(position, length), &next_codepoint, | |
1114 &return_result); | |
1115 | |
1116 assembler->Bind(&next_codepoint); | |
1117 { | |
1118 Node* ch = LoadSurrogatePairAt(assembler, string, length, position); | |
1119 Node* value = CreateStringFromSurrogatePair(assembler, ch); | |
1120 var_value.Bind(value); | |
1121 Node* length = | |
1122 assembler->LoadAndUntagObjectField(value, String::kLengthOffset); | |
Benedikt Meurer
2016/09/26 04:15:40
Nit: You can avoid some untagging and tagging here
caitp
2016/09/26 14:33:54
Acknowledged. (but, they still get untagged for th
| |
1123 assembler->StoreObjectFieldNoWriteBarrier( | |
1124 iterator, JSStringIterator::kNextIndexOffset, | |
1125 assembler->SmiFromWord32(assembler->Int32Add(position, length))); | |
1126 var_done.Bind(assembler->BooleanConstant(false)); | |
1127 assembler->Goto(&return_result); | |
1128 } | |
1129 | |
1130 assembler->Bind(&return_result); | |
1131 { | |
1132 Node* native_context = assembler->LoadNativeContext(context); | |
1133 Node* map = assembler->LoadFixedArrayElement( | |
1134 native_context, | |
1135 assembler->IntPtrConstant(Context::ITERATOR_RESULT_MAP_INDEX), 0, | |
1136 CodeStubAssembler::INTPTR_PARAMETERS); | |
1137 Node* result = assembler->Allocate(JSIteratorResult::kSize); | |
1138 assembler->StoreMapNoWriteBarrier(result, map); | |
1139 assembler->StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset, | |
1140 Heap::kEmptyFixedArrayRootIndex); | |
1141 assembler->StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset, | |
1142 Heap::kEmptyFixedArrayRootIndex); | |
1143 assembler->StoreObjectFieldNoWriteBarrier( | |
1144 result, JSIteratorResult::kValueOffset, var_value.value()); | |
1145 assembler->StoreObjectFieldNoWriteBarrier( | |
1146 result, JSIteratorResult::kDoneOffset, var_done.value()); | |
1147 assembler->Return(result); | |
1148 } | |
1149 | |
1150 assembler->Bind(&throw_bad_receiver); | |
1151 { | |
1152 // The {receiver} is not a valid JSGeneratorObject. | |
1153 Node* result = assembler->CallRuntime( | |
1154 Runtime::kThrowIncompatibleMethodReceiver, context, | |
1155 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( | |
1156 "String Iterator.prototype.next", TENURED)), | |
1157 iterator); | |
1158 assembler->Return(result); // Never reached. | |
1159 } | |
671 } | 1160 } |
672 | 1161 |
673 } // namespace internal | 1162 } // namespace internal |
674 } // namespace v8 | 1163 } // namespace v8 |
OLD | NEW |