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 498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 |
OLD | NEW |