Chromium Code Reviews| 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* index = assembler->Int32Constant(Context::STRING_ITERATOR_MAP_INDEX); | |
| 706 Node* map = assembler->LoadFixedArrayElement( | |
| 707 native_context, index, 0, CodeStubAssembler::INTPTR_PARAMETERS); | |
| 708 Node* iterator = assembler->Allocate(JSStringIterator::kSize); | |
| 709 assembler->StoreMapNoWriteBarrier(iterator, map); | |
| 710 assembler->StoreObjectFieldRoot(iterator, JSValue::kPropertiesOffset, | |
| 711 Heap::kEmptyFixedArrayRootIndex); | |
| 712 assembler->StoreObjectFieldRoot(iterator, JSObject::kElementsOffset, | |
| 713 Heap::kEmptyFixedArrayRootIndex); | |
| 714 assembler->StoreObjectField(iterator, JSStringIterator::kStringOffset, | |
|
Benedikt Meurer
2016/09/23 18:14:53
This doesn't need a write barrier, since the objec
caitp
2016/09/23 19:14:16
Done.
| |
| 715 var_string.value()); | |
| 716 | |
| 717 assembler->StoreObjectField(iterator, JSStringIterator::kNextIndexOffset, | |
|
Benedikt Meurer
2016/09/23 18:14:53
This doesn't need a write barrier, you can safely
caitp
2016/09/23 19:14:16
Done.
| |
| 718 assembler->SmiFromWord32(var_index.value())); | |
| 719 assembler->Return(iterator); | |
| 720 } | |
| 721 } | |
| 722 | |
| 723 namespace { | |
| 724 | |
| 725 enum class UnicodeEncoding { | |
| 726 UTF16, // high 16bits trail surrogate, low 16bits lead surrogate | |
| 727 UTF32 | |
| 728 }; | |
| 729 | |
| 730 // Return the |String| containing a single {codepoint}, which may be encoded | |
| 731 // as one of the following: a single UTF16 code unit, a |word32| with the | |
| 732 // high 16 bits set to the trailing surrogate, and low 16 bits set to the lead | |
| 733 // surrogate, or a single UTF32-encoded codepoint. | |
| 734 static compiler::Node* CreateStringFromCodePointInternal( | |
|
Benedikt Meurer
2016/09/23 03:46:24
You don't need static inside an anonymous namespac
caitp
2016/09/23 10:14:28
The UnicodeEncoding thing is there to control how
caitp
2016/09/23 19:14:16
The UnicodeEncoding thing is there to control how
Benedikt Meurer
2016/09/26 04:15:40
Acknowledged.
| |
| 735 CodeStubAssembler* assembler, compiler::Node* codepoint, | |
| 736 UnicodeEncoding encoding) { | |
| 737 typedef CodeStubAssembler::Label Label; | |
| 738 typedef compiler::Node Node; | |
| 739 typedef CodeStubAssembler::Variable Variable; | |
| 740 | |
| 741 Variable var_result(assembler, MachineRepresentation::kTagged); | |
| 742 var_result.Bind(assembler->EmptyStringConstant()); | |
| 743 | |
| 744 Label if_isonebyte(assembler), if_istwobyte(assembler), | |
| 745 return_result(assembler); | |
| 746 | |
| 747 assembler->Branch( | |
| 748 assembler->Uint32LessThan(codepoint, assembler->Int32Constant(0x100)), | |
| 749 &if_isonebyte, &if_istwobyte); | |
| 750 | |
| 751 assembler->Bind(&if_isonebyte); | |
| 752 { | |
| 753 Node* value = assembler->AllocateSeqOneByteString(1); | |
| 754 assembler->StoreNoWriteBarrier( | |
| 755 MachineRepresentation::kWord8, value, | |
| 756 assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - | |
| 757 kHeapObjectTag), | |
| 758 codepoint); | |
| 759 var_result.Bind(value); | |
| 760 assembler->Goto(&return_result); | |
| 761 } | |
| 762 | |
| 763 assembler->Bind(&if_istwobyte); | |
| 764 { | |
| 765 Label if_isdouble(assembler), if_issingle(assembler); | |
| 766 assembler->Branch( | |
| 767 assembler->Uint32LessThan(codepoint, assembler->Int32Constant(0x10000)), | |
| 768 &if_issingle, &if_isdouble); | |
| 769 | |
| 770 assembler->Bind(&if_issingle); | |
| 771 { | |
| 772 Node* value = assembler->AllocateSeqTwoByteString(1); | |
| 773 assembler->StoreNoWriteBarrier( | |
| 774 MachineRepresentation::kWord16, value, | |
| 775 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
| 776 kHeapObjectTag), | |
| 777 codepoint); | |
| 778 var_result.Bind(value); | |
| 779 assembler->Goto(&return_result); | |
| 780 } | |
| 781 | |
| 782 assembler->Bind(&if_isdouble); | |
| 783 { | |
| 784 switch (encoding) { | |
| 785 case UnicodeEncoding::UTF16: | |
| 786 break; | |
| 787 case UnicodeEncoding::UTF32: { | |
| 788 // Convert UTF32 to UTF16 code units, and store as a 32 bit word. | |
| 789 Node* lead_offset = | |
|
caitp
2016/09/23 19:14:16
This code here in particular should be very useful
| |
| 790 assembler->Int32Constant(0xD800 - (0x10000 >> 10)); | |
| 791 | |
| 792 Node* lead = assembler->Int32Add( | |
| 793 assembler->WordShr(codepoint, assembler->Int32Constant(10)), | |
| 794 lead_offset); | |
| 795 | |
| 796 Node* trail = assembler->Int32Add( | |
| 797 assembler->Word32And(codepoint, assembler->Int32Constant(0x3FF)), | |
| 798 assembler->Int32Constant(0xDC00)); | |
| 799 | |
| 800 codepoint = assembler->Word32Or( | |
| 801 assembler->WordShl(trail, assembler->Int32Constant(16)), lead); | |
| 802 } | |
| 803 default: | |
| 804 UNREACHABLE(); | |
| 805 } | |
| 806 | |
| 807 Node* value = assembler->AllocateSeqTwoByteString(2); | |
| 808 assembler->StoreNoWriteBarrier( | |
| 809 MachineRepresentation::kWord32, value, | |
| 810 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
| 811 kHeapObjectTag), | |
| 812 codepoint); | |
| 813 var_result.Bind(value); | |
| 814 assembler->Goto(&return_result); | |
| 815 } | |
| 816 } | |
| 817 | |
| 818 assembler->Bind(&return_result); | |
| 819 return var_result.value(); | |
| 820 } | |
| 821 | |
| 822 static compiler::Node* CreateStringFromSurrogatePair( | |
| 823 CodeStubAssembler* assembler, compiler::Node* code_units) { | |
| 824 return CreateStringFromCodePointInternal(assembler, code_units, | |
| 825 UnicodeEncoding::UTF16); | |
| 826 } | |
| 827 | |
| 828 // Return the |word32| codepoint at {index}. Supports SeqStrings and | |
| 829 // ExternalStrings. | |
| 830 static compiler::Node* LoadSurrogatePairInternal(CodeStubAssembler* assembler, | |
| 831 compiler::Node* string, | |
| 832 compiler::Node* length, | |
| 833 compiler::Node* index, | |
| 834 UnicodeEncoding encoding) { | |
| 835 typedef CodeStubAssembler::Label Label; | |
| 836 typedef compiler::Node Node; | |
| 837 typedef CodeStubAssembler::Variable Variable; | |
| 838 Label handle_surrogate_pair(assembler), return_result(assembler); | |
| 839 Variable var_result(assembler, MachineRepresentation::kWord32); | |
| 840 Variable var_trail(assembler, MachineRepresentation::kWord16); | |
| 841 var_result.Bind(assembler->Int32Constant(0)); | |
| 842 var_trail.Bind(assembler->Int32Constant(0)); | |
| 843 | |
| 844 Node* string_instance_type = assembler->LoadInstanceType(string); | |
| 845 | |
| 846 Label if_stringissequential(assembler), if_stringisexternal(assembler); | |
| 847 assembler->Branch(assembler->Word32Equal( | |
| 848 assembler->Word32And(string_instance_type, | |
| 849 assembler->Int32Constant( | |
| 850 kStringRepresentationMask)), | |
| 851 assembler->Int32Constant(kSeqStringTag)), | |
| 852 &if_stringissequential, &if_stringisexternal); | |
| 853 | |
| 854 assembler->Bind(&if_stringissequential); | |
| 855 { | |
| 856 Label if_stringisonebyte(assembler), if_stringistwobyte(assembler); | |
| 857 assembler->Branch( | |
| 858 assembler->Word32Equal( | |
| 859 assembler->Word32And(string_instance_type, | |
| 860 assembler->Int32Constant(kStringEncodingMask)), | |
| 861 assembler->Int32Constant(kOneByteStringTag)), | |
| 862 &if_stringisonebyte, &if_stringistwobyte); | |
| 863 | |
| 864 assembler->Bind(&if_stringisonebyte); | |
| 865 { | |
| 866 var_result.Bind(assembler->Load( | |
| 867 MachineType::Uint8(), string, | |
| 868 assembler->IntPtrAdd( | |
| 869 index, assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - | |
| 870 kHeapObjectTag)))); | |
| 871 assembler->Goto(&return_result); | |
| 872 } | |
| 873 | |
| 874 assembler->Bind(&if_stringistwobyte); | |
| 875 { | |
| 876 Node* lead = assembler->Load( | |
| 877 MachineType::Uint16(), string, | |
| 878 assembler->IntPtrAdd( | |
| 879 assembler->WordShl(index, assembler->IntPtrConstant(1)), | |
| 880 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
| 881 kHeapObjectTag))); | |
| 882 var_result.Bind(lead); | |
| 883 Node* next_pos = assembler->Int32Add(index, assembler->Int32Constant(1)); | |
| 884 | |
| 885 Label if_isdoublecodeunit(assembler); | |
| 886 assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length), | |
| 887 &return_result); | |
| 888 assembler->GotoIf( | |
| 889 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)), | |
| 890 &return_result); | |
| 891 assembler->Branch( | |
| 892 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00)), | |
| 893 &if_isdoublecodeunit, &return_result); | |
| 894 | |
| 895 assembler->Bind(&if_isdoublecodeunit); | |
| 896 { | |
| 897 Node* trail = assembler->Load( | |
| 898 MachineType::Uint16(), string, | |
| 899 assembler->IntPtrAdd( | |
| 900 assembler->WordShl(next_pos, assembler->IntPtrConstant(1)), | |
| 901 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
| 902 kHeapObjectTag))); | |
| 903 assembler->GotoIf( | |
| 904 assembler->Uint32LessThan(trail, assembler->Int32Constant(0xDC00)), | |
| 905 &return_result); | |
| 906 assembler->GotoIf(assembler->Uint32GreaterThanOrEqual( | |
| 907 trail, assembler->Int32Constant(0xE000)), | |
| 908 &return_result); | |
| 909 | |
| 910 var_trail.Bind(trail); | |
| 911 assembler->Goto(&handle_surrogate_pair); | |
| 912 } | |
| 913 } | |
| 914 } | |
| 915 | |
| 916 assembler->Bind(&if_stringisexternal); | |
| 917 { | |
| 918 assembler->Assert(assembler->Word32Equal( | |
| 919 assembler->Word32And( | |
| 920 string_instance_type, | |
| 921 assembler->Int32Constant(kStringRepresentationMask)), | |
| 922 assembler->Int32Constant(kExternalStringTag))); | |
| 923 Label if_stringisshort(assembler), if_stringisnotshort(assembler); | |
| 924 | |
| 925 assembler->Branch(assembler->Word32Equal( | |
| 926 assembler->Word32And(string_instance_type, | |
| 927 assembler->Int32Constant( | |
| 928 kShortExternalStringMask)), | |
| 929 assembler->Int32Constant(0)), | |
| 930 &if_stringisshort, &if_stringisnotshort); | |
| 931 | |
| 932 assembler->Bind(&if_stringisshort); | |
| 933 { | |
| 934 // Load the actual resource data from the {string}. | |
| 935 Node* string_resource_data = assembler->LoadObjectField( | |
| 936 string, ExternalString::kResourceDataOffset, MachineType::Pointer()); | |
| 937 | |
| 938 Label if_stringistwobyte(assembler), if_stringisonebyte(assembler); | |
| 939 assembler->Branch(assembler->Word32Equal( | |
| 940 assembler->Word32And( | |
| 941 string_instance_type, | |
| 942 assembler->Int32Constant(kStringEncodingMask)), | |
| 943 assembler->Int32Constant(kTwoByteStringTag)), | |
| 944 &if_stringistwobyte, &if_stringisonebyte); | |
| 945 | |
| 946 assembler->Bind(&if_stringisonebyte); | |
| 947 { | |
| 948 var_result.Bind( | |
| 949 assembler->Load(MachineType::Uint8(), string_resource_data, index)); | |
| 950 assembler->Goto(&return_result); | |
| 951 } | |
| 952 | |
| 953 assembler->Bind(&if_stringistwobyte); | |
| 954 { | |
| 955 Label if_isdoublecodeunit(assembler); | |
| 956 Node* lead = assembler->Load( | |
| 957 MachineType::Uint16(), string_resource_data, | |
| 958 assembler->WordShl(index, assembler->IntPtrConstant(1))); | |
| 959 var_result.Bind(lead); | |
| 960 Node* next_pos = | |
| 961 assembler->Int32Add(index, assembler->Int32Constant(1)); | |
| 962 | |
| 963 assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length), | |
| 964 &return_result); | |
| 965 assembler->GotoIf( | |
| 966 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)), | |
| 967 &return_result); | |
| 968 assembler->Branch( | |
| 969 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00)), | |
| 970 &if_isdoublecodeunit, &return_result); | |
| 971 | |
| 972 assembler->Bind(&if_isdoublecodeunit); | |
| 973 { | |
| 974 Node* trail = assembler->Load( | |
| 975 MachineType::Uint16(), string, | |
| 976 assembler->IntPtrAdd( | |
| 977 assembler->WordShl(next_pos, assembler->IntPtrConstant(1)), | |
| 978 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
| 979 kHeapObjectTag))); | |
| 980 assembler->GotoIf(assembler->Uint32LessThan( | |
| 981 trail, assembler->Int32Constant(0xDC00)), | |
| 982 &return_result); | |
| 983 assembler->GotoIf(assembler->Uint32GreaterThanOrEqual( | |
| 984 trail, assembler->Int32Constant(0xE000)), | |
| 985 &return_result); | |
| 986 | |
| 987 var_trail.Bind(trail); | |
| 988 assembler->Goto(&handle_surrogate_pair); | |
| 989 } | |
| 990 } | |
| 991 } | |
| 992 | |
| 993 assembler->Bind(&if_stringisnotshort); | |
| 994 { | |
| 995 Label if_isdoublecodeunit(assembler); | |
| 996 Node* lead = assembler->SmiToWord32(assembler->CallRuntime( | |
| 997 Runtime::kExternalStringGetChar, assembler->NoContextConstant(), | |
| 998 string, assembler->SmiTag(index))); | |
| 999 var_result.Bind(lead); | |
| 1000 Node* next_pos = assembler->Int32Add(index, assembler->Int32Constant(1)); | |
| 1001 | |
| 1002 assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length), | |
| 1003 &return_result); | |
| 1004 assembler->GotoIf( | |
| 1005 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)), | |
| 1006 &return_result); | |
| 1007 assembler->Branch(assembler->Uint32GreaterThanOrEqual( | |
| 1008 lead, assembler->Int32Constant(0xDC00)), | |
| 1009 &return_result, &if_isdoublecodeunit); | |
| 1010 | |
| 1011 assembler->Bind(&if_isdoublecodeunit); | |
| 1012 { | |
| 1013 Node* trail = assembler->SmiToWord32(assembler->CallRuntime( | |
| 1014 Runtime::kExternalStringGetChar, assembler->NoContextConstant(), | |
| 1015 string, assembler->SmiTag(next_pos))); | |
| 1016 assembler->GotoIf( | |
| 1017 assembler->Uint32LessThan(trail, assembler->Int32Constant(0xDC00)), | |
| 1018 &return_result); | |
| 1019 assembler->GotoIf(assembler->Uint32GreaterThanOrEqual( | |
| 1020 trail, assembler->Int32Constant(0xE000)), | |
| 1021 &return_result); | |
| 1022 var_trail.Bind(trail); | |
| 1023 assembler->Goto(&handle_surrogate_pair); | |
| 1024 } | |
| 1025 } | |
| 1026 } | |
| 1027 | |
| 1028 assembler->Bind(&handle_surrogate_pair); | |
| 1029 { | |
| 1030 Node* lead = var_result.value(); | |
| 1031 Node* trail = var_trail.value(); | |
| 1032 #ifdef ENABLE_SLOW_DCHECKS | |
| 1033 // Check that this path is only taken if a surrogate pair is found | |
| 1034 assembler->Assert(assembler->Uint32GreaterThanOrEqual( | |
| 1035 lead, assembler->Int32Constant(0xD800))); | |
| 1036 assembler->Assert( | |
| 1037 assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00))); | |
| 1038 assembler->Assert(assembler->Uint32GreaterThanOrEqual( | |
| 1039 trail, assembler->Int32Constant(0xDC00))); | |
| 1040 assembler->Assert( | |
| 1041 assembler->Uint32LessThan(trail, assembler->Int32Constant(0xE000))); | |
| 1042 #endif | |
| 1043 | |
| 1044 switch (encoding) { | |
| 1045 case UnicodeEncoding::UTF16: | |
| 1046 var_result.Bind(assembler->WordOr( | |
| 1047 assembler->WordShl(trail, assembler->Int32Constant(16)), lead)); | |
| 1048 break; | |
| 1049 | |
| 1050 case UnicodeEncoding::UTF32: { | |
| 1051 // Convert UTF16 surrogate pair into |word32| code point, encoded as | |
| 1052 // UTF32. | |
| 1053 Node* surrogate_offset = | |
| 1054 assembler->Int32Constant(0x10000 - (0xD800 << 10) - 0xDC00); | |
| 1055 | |
| 1056 // (lead << 10) + trail + SURROGATE_OFFSET | |
| 1057 var_result.Bind(assembler->Int32Add( | |
| 1058 assembler->WordShl(lead, assembler->Int32Constant(10)), | |
| 1059 assembler->Int32Add(trail, surrogate_offset))); | |
| 1060 break; | |
| 1061 } | |
| 1062 } | |
| 1063 assembler->Goto(&return_result); | |
| 1064 } | |
| 1065 | |
| 1066 assembler->Bind(&return_result); | |
| 1067 return var_result.value(); | |
| 1068 } | |
| 1069 | |
| 1070 static compiler::Node* LoadSurrogatePairAt(CodeStubAssembler* assembler, | |
| 1071 compiler::Node* string, | |
| 1072 compiler::Node* length, | |
| 1073 compiler::Node* index) { | |
| 1074 return LoadSurrogatePairInternal(assembler, string, length, index, | |
| 1075 UnicodeEncoding::UTF16); | |
| 1076 } | |
| 1077 | |
| 1078 } // namespace | |
| 1079 | |
| 1080 void Builtins::Generate_StringIteratorPrototypeNext( | |
| 1081 CodeStubAssembler* assembler) { | |
| 1082 typedef CodeStubAssembler::Label Label; | |
| 1083 typedef compiler::Node Node; | |
| 1084 typedef CodeStubAssembler::Variable Variable; | |
| 1085 | |
| 1086 Variable var_value(assembler, MachineRepresentation::kTagged); | |
| 1087 Variable var_done(assembler, MachineRepresentation::kTagged); | |
| 1088 | |
| 1089 var_value.Bind(assembler->UndefinedConstant()); | |
| 1090 var_done.Bind(assembler->BooleanConstant(true)); | |
| 1091 | |
| 1092 Label throw_bad_receiver(assembler), next_codepoint(assembler), | |
| 1093 return_result(assembler); | |
| 1094 | |
| 1095 Node* iterator = assembler->Parameter(0); | |
| 1096 Node* context = assembler->Parameter(3); | |
| 1097 | |
| 1098 assembler->GotoIf(assembler->WordIsSmi(iterator), &throw_bad_receiver); | |
| 1099 assembler->GotoUnless( | |
| 1100 assembler->WordEqual(assembler->LoadInstanceType(iterator), | |
| 1101 assembler->Int32Constant(JS_STRING_ITERATOR_TYPE)), | |
| 1102 &throw_bad_receiver); | |
| 1103 | |
| 1104 Node* string = | |
| 1105 assembler->LoadObjectField(iterator, JSStringIterator::kStringOffset); | |
| 1106 Node* position = assembler->LoadAndUntagObjectField( | |
| 1107 iterator, JSStringIterator::kNextIndexOffset); | |
| 1108 Node* length = | |
| 1109 assembler->LoadAndUntagObjectField(string, String::kLengthOffset); | |
| 1110 | |
| 1111 assembler->Branch(assembler->Int32LessThan(position, length), &next_codepoint, | |
| 1112 &return_result); | |
| 1113 | |
| 1114 assembler->Bind(&next_codepoint); | |
| 1115 { | |
| 1116 Node* ch = LoadSurrogatePairAt(assembler, string, length, position); | |
| 1117 Node* value = CreateStringFromSurrogatePair(assembler, ch); | |
| 1118 var_value.Bind(value); | |
| 1119 Node* length = | |
| 1120 assembler->LoadAndUntagObjectField(value, String::kLengthOffset); | |
| 1121 assembler->StoreObjectFieldNoWriteBarrier( | |
| 1122 iterator, JSStringIterator::kNextIndexOffset, | |
| 1123 assembler->SmiFromWord32(assembler->Int32Add(position, length))); | |
| 1124 var_done.Bind(assembler->BooleanConstant(false)); | |
| 1125 assembler->Goto(&return_result); | |
| 1126 } | |
| 1127 | |
| 1128 assembler->Bind(&return_result); | |
| 1129 { | |
| 1130 Node* native_context = assembler->LoadNativeContext(context); | |
| 1131 Node* map = assembler->LoadFixedArrayElement( | |
| 1132 native_context, | |
| 1133 assembler->IntPtrConstant(Context::ITERATOR_RESULT_MAP_INDEX), 0, | |
| 1134 CodeStubAssembler::INTPTR_PARAMETERS); | |
| 1135 Node* result = assembler->Allocate(JSIteratorResult::kSize); | |
| 1136 assembler->StoreMapNoWriteBarrier(result, map); | |
| 1137 assembler->StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset, | |
| 1138 Heap::kEmptyFixedArrayRootIndex); | |
| 1139 assembler->StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset, | |
| 1140 Heap::kEmptyFixedArrayRootIndex); | |
| 1141 assembler->StoreObjectField(result, JSIteratorResult::kValueOffset, | |
|
Benedikt Meurer
2016/09/23 18:14:53
You can skip write barrier for these two stores be
caitp
2016/09/23 19:14:16
Done.
| |
| 1142 var_value.value()); | |
| 1143 assembler->StoreObjectField(result, JSIteratorResult::kDoneOffset, | |
| 1144 var_done.value()); | |
| 1145 assembler->Return(result); | |
| 1146 } | |
| 1147 | |
| 1148 assembler->Bind(&throw_bad_receiver); | |
| 1149 { | |
| 1150 // The {receiver} is not a valid JSGeneratorObject. | |
| 1151 Node* result = assembler->CallRuntime( | |
| 1152 Runtime::kThrowIncompatibleMethodReceiver, context, | |
| 1153 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( | |
| 1154 "String Iterator.prototype.next", TENURED)), | |
| 1155 iterator); | |
| 1156 assembler->Return(result); // Never reached. | |
| 1157 } | |
| 671 } | 1158 } |
| 672 | 1159 |
| 673 } // namespace internal | 1160 } // namespace internal |
| 674 } // namespace v8 | 1161 } // namespace v8 |
| OLD | NEW |