OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 #if V8_TARGET_ARCH_ARM64 | 5 #if V8_TARGET_ARCH_ARM64 |
6 | 6 |
7 #include "src/code-stubs.h" | 7 #include "src/code-stubs.h" |
8 #include "src/api-arguments.h" | 8 #include "src/api-arguments.h" |
9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
(...skipping 2655 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2666 // Compute the entry point of the rewritten stub. | 2666 // Compute the entry point of the rewritten stub. |
2667 __ Add(stub_entry, x0, Code::kHeaderSize - kHeapObjectTag); | 2667 __ Add(stub_entry, x0, Code::kHeaderSize - kHeapObjectTag); |
2668 // Restore caller-saved registers. | 2668 // Restore caller-saved registers. |
2669 __ Pop(lr, x0, x1); | 2669 __ Pop(lr, x0, x1); |
2670 } | 2670 } |
2671 | 2671 |
2672 // Tail-call to the new stub. | 2672 // Tail-call to the new stub. |
2673 __ Jump(stub_entry); | 2673 __ Jump(stub_entry); |
2674 } | 2674 } |
2675 | 2675 |
2676 | |
2677 void SubStringStub::Generate(MacroAssembler* masm) { | |
2678 ASM_LOCATION("SubStringStub::Generate"); | |
2679 Label runtime; | |
2680 | |
2681 // Stack frame on entry. | |
2682 // lr: return address | |
2683 // jssp[0]: substring "to" offset | |
2684 // jssp[8]: substring "from" offset | |
2685 // jssp[16]: pointer to string object | |
2686 | |
2687 // This stub is called from the native-call %_SubString(...), so | |
2688 // nothing can be assumed about the arguments. It is tested that: | |
2689 // "string" is a sequential string, | |
2690 // both "from" and "to" are smis, and | |
2691 // 0 <= from <= to <= string.length (in debug mode.) | |
2692 // If any of these assumptions fail, we call the runtime system. | |
2693 | |
2694 static const int kToOffset = 0 * kPointerSize; | |
2695 static const int kFromOffset = 1 * kPointerSize; | |
2696 static const int kStringOffset = 2 * kPointerSize; | |
2697 | |
2698 Register to = x0; | |
2699 Register from = x15; | |
2700 Register input_string = x10; | |
2701 Register input_length = x11; | |
2702 Register input_type = x12; | |
2703 Register result_string = x0; | |
2704 Register result_length = x1; | |
2705 Register temp = x3; | |
2706 | |
2707 __ Peek(to, kToOffset); | |
2708 __ Peek(from, kFromOffset); | |
2709 | |
2710 // Check that both from and to are smis. If not, jump to runtime. | |
2711 __ JumpIfEitherNotSmi(from, to, &runtime); | |
2712 __ SmiUntag(from); | |
2713 __ SmiUntag(to); | |
2714 | |
2715 // Calculate difference between from and to. If to < from, branch to runtime. | |
2716 __ Subs(result_length, to, from); | |
2717 __ B(mi, &runtime); | |
2718 | |
2719 // Check from is positive. | |
2720 __ Tbnz(from, kWSignBit, &runtime); | |
2721 | |
2722 // Make sure first argument is a string. | |
2723 __ Peek(input_string, kStringOffset); | |
2724 __ JumpIfSmi(input_string, &runtime); | |
2725 __ IsObjectJSStringType(input_string, input_type, &runtime); | |
2726 | |
2727 Label single_char; | |
2728 __ Cmp(result_length, 1); | |
2729 __ B(eq, &single_char); | |
2730 | |
2731 // Short-cut for the case of trivial substring. | |
2732 Label return_x0; | |
2733 __ Ldrsw(input_length, | |
2734 UntagSmiFieldMemOperand(input_string, String::kLengthOffset)); | |
2735 | |
2736 __ Cmp(result_length, input_length); | |
2737 __ CmovX(x0, input_string, eq); | |
2738 // Return original string. | |
2739 __ B(eq, &return_x0); | |
2740 | |
2741 // Longer than original string's length or negative: unsafe arguments. | |
2742 __ B(hi, &runtime); | |
2743 | |
2744 // Shorter than original string's length: an actual substring. | |
2745 | |
2746 // x0 to substring end character offset | |
2747 // x1 result_length length of substring result | |
2748 // x10 input_string pointer to input string object | |
2749 // x10 unpacked_string pointer to unpacked string object | |
2750 // x11 input_length length of input string | |
2751 // x12 input_type instance type of input string | |
2752 // x15 from substring start character offset | |
2753 | |
2754 // Deal with different string types: update the index if necessary and put | |
2755 // the underlying string into register unpacked_string. | |
2756 Label underlying_unpacked, sliced_string, seq_or_external_string; | |
2757 Label update_instance_type; | |
2758 // If the string is not indirect, it can only be sequential or external. | |
2759 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); | |
2760 STATIC_ASSERT(kIsIndirectStringMask != 0); | |
2761 | |
2762 // Test for string types, and branch/fall through to appropriate unpacking | |
2763 // code. | |
2764 __ Tst(input_type, kIsIndirectStringMask); | |
2765 __ B(eq, &seq_or_external_string); | |
2766 __ Tst(input_type, kSlicedNotConsMask); | |
2767 __ B(ne, &sliced_string); | |
2768 | |
2769 Register unpacked_string = input_string; | |
2770 | |
2771 // Cons string. Check whether it is flat, then fetch first part. | |
2772 __ Ldr(temp, FieldMemOperand(input_string, ConsString::kSecondOffset)); | |
2773 __ JumpIfNotRoot(temp, Heap::kempty_stringRootIndex, &runtime); | |
2774 __ Ldr(unpacked_string, | |
2775 FieldMemOperand(input_string, ConsString::kFirstOffset)); | |
2776 __ B(&update_instance_type); | |
2777 | |
2778 __ Bind(&sliced_string); | |
2779 // Sliced string. Fetch parent and correct start index by offset. | |
2780 __ Ldrsw(temp, | |
2781 UntagSmiFieldMemOperand(input_string, SlicedString::kOffsetOffset)); | |
2782 __ Add(from, from, temp); | |
2783 __ Ldr(unpacked_string, | |
2784 FieldMemOperand(input_string, SlicedString::kParentOffset)); | |
2785 | |
2786 __ Bind(&update_instance_type); | |
2787 __ Ldr(temp, FieldMemOperand(unpacked_string, HeapObject::kMapOffset)); | |
2788 __ Ldrb(input_type, FieldMemOperand(temp, Map::kInstanceTypeOffset)); | |
2789 // Now control must go to &underlying_unpacked. Since the no code is generated | |
2790 // before then we fall through instead of generating a useless branch. | |
2791 | |
2792 __ Bind(&seq_or_external_string); | |
2793 // Sequential or external string. Registers unpacked_string and input_string | |
2794 // alias, so there's nothing to do here. | |
2795 // Note that if code is added here, the above code must be updated. | |
2796 | |
2797 // x0 result_string pointer to result string object (uninit) | |
2798 // x1 result_length length of substring result | |
2799 // x10 unpacked_string pointer to unpacked string object | |
2800 // x11 input_length length of input string | |
2801 // x12 input_type instance type of input string | |
2802 // x15 from substring start character offset | |
2803 __ Bind(&underlying_unpacked); | |
2804 | |
2805 if (FLAG_string_slices) { | |
2806 Label copy_routine; | |
2807 __ Cmp(result_length, SlicedString::kMinLength); | |
2808 // Short slice. Copy instead of slicing. | |
2809 __ B(lt, ©_routine); | |
2810 // Allocate new sliced string. At this point we do not reload the instance | |
2811 // type including the string encoding because we simply rely on the info | |
2812 // provided by the original string. It does not matter if the original | |
2813 // string's encoding is wrong because we always have to recheck encoding of | |
2814 // the newly created string's parent anyway due to externalized strings. | |
2815 Label two_byte_slice, set_slice_header; | |
2816 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); | |
2817 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | |
2818 __ Tbz(input_type, MaskToBit(kStringEncodingMask), &two_byte_slice); | |
2819 __ AllocateOneByteSlicedString(result_string, result_length, x3, x4, | |
2820 &runtime); | |
2821 __ B(&set_slice_header); | |
2822 | |
2823 __ Bind(&two_byte_slice); | |
2824 __ AllocateTwoByteSlicedString(result_string, result_length, x3, x4, | |
2825 &runtime); | |
2826 | |
2827 __ Bind(&set_slice_header); | |
2828 __ SmiTag(from); | |
2829 __ Str(from, FieldMemOperand(result_string, SlicedString::kOffsetOffset)); | |
2830 __ Str(unpacked_string, | |
2831 FieldMemOperand(result_string, SlicedString::kParentOffset)); | |
2832 __ B(&return_x0); | |
2833 | |
2834 __ Bind(©_routine); | |
2835 } | |
2836 | |
2837 // x0 result_string pointer to result string object (uninit) | |
2838 // x1 result_length length of substring result | |
2839 // x10 unpacked_string pointer to unpacked string object | |
2840 // x11 input_length length of input string | |
2841 // x12 input_type instance type of input string | |
2842 // x13 unpacked_char0 pointer to first char of unpacked string (uninit) | |
2843 // x13 substring_char0 pointer to first char of substring (uninit) | |
2844 // x14 result_char0 pointer to first char of result (uninit) | |
2845 // x15 from substring start character offset | |
2846 Register unpacked_char0 = x13; | |
2847 Register substring_char0 = x13; | |
2848 Register result_char0 = x14; | |
2849 Label two_byte_sequential, sequential_string, allocate_result; | |
2850 STATIC_ASSERT(kExternalStringTag != 0); | |
2851 STATIC_ASSERT(kSeqStringTag == 0); | |
2852 | |
2853 __ Tst(input_type, kExternalStringTag); | |
2854 __ B(eq, &sequential_string); | |
2855 | |
2856 __ Tst(input_type, kShortExternalStringTag); | |
2857 __ B(ne, &runtime); | |
2858 __ Ldr(unpacked_char0, | |
2859 FieldMemOperand(unpacked_string, ExternalString::kResourceDataOffset)); | |
2860 // unpacked_char0 points to the first character of the underlying string. | |
2861 __ B(&allocate_result); | |
2862 | |
2863 __ Bind(&sequential_string); | |
2864 // Locate first character of underlying subject string. | |
2865 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | |
2866 __ Add(unpacked_char0, unpacked_string, | |
2867 SeqOneByteString::kHeaderSize - kHeapObjectTag); | |
2868 | |
2869 __ Bind(&allocate_result); | |
2870 // Sequential one-byte string. Allocate the result. | |
2871 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); | |
2872 __ Tbz(input_type, MaskToBit(kStringEncodingMask), &two_byte_sequential); | |
2873 | |
2874 // Allocate and copy the resulting one-byte string. | |
2875 __ AllocateOneByteString(result_string, result_length, x3, x4, x5, &runtime); | |
2876 | |
2877 // Locate first character of substring to copy. | |
2878 __ Add(substring_char0, unpacked_char0, from); | |
2879 | |
2880 // Locate first character of result. | |
2881 __ Add(result_char0, result_string, | |
2882 SeqOneByteString::kHeaderSize - kHeapObjectTag); | |
2883 | |
2884 STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); | |
2885 __ CopyBytes(result_char0, substring_char0, result_length, x3, kCopyLong); | |
2886 __ B(&return_x0); | |
2887 | |
2888 // Allocate and copy the resulting two-byte string. | |
2889 __ Bind(&two_byte_sequential); | |
2890 __ AllocateTwoByteString(result_string, result_length, x3, x4, x5, &runtime); | |
2891 | |
2892 // Locate first character of substring to copy. | |
2893 __ Add(substring_char0, unpacked_char0, Operand(from, LSL, 1)); | |
2894 | |
2895 // Locate first character of result. | |
2896 __ Add(result_char0, result_string, | |
2897 SeqTwoByteString::kHeaderSize - kHeapObjectTag); | |
2898 | |
2899 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); | |
2900 __ Add(result_length, result_length, result_length); | |
2901 __ CopyBytes(result_char0, substring_char0, result_length, x3, kCopyLong); | |
2902 | |
2903 __ Bind(&return_x0); | |
2904 Counters* counters = isolate()->counters(); | |
2905 __ IncrementCounter(counters->sub_string_native(), 1, x3, x4); | |
2906 __ Drop(3); | |
2907 __ Ret(); | |
2908 | |
2909 __ Bind(&runtime); | |
2910 __ TailCallRuntime(Runtime::kSubString); | |
2911 | |
2912 __ bind(&single_char); | |
2913 // x1: result_length | |
2914 // x10: input_string | |
2915 // x12: input_type | |
2916 // x15: from (untagged) | |
2917 __ SmiTag(from); | |
2918 StringCharAtGenerator generator(input_string, from, result_length, x0, | |
2919 &runtime, &runtime, &runtime, | |
2920 RECEIVER_IS_STRING); | |
2921 generator.GenerateFast(masm); | |
2922 __ Drop(3); | |
2923 __ Ret(); | |
2924 generator.SkipSlow(masm, &runtime); | |
2925 } | |
2926 | |
2927 void ToStringStub::Generate(MacroAssembler* masm) { | 2676 void ToStringStub::Generate(MacroAssembler* masm) { |
2928 // The ToString stub takes one argument in x0. | 2677 // The ToString stub takes one argument in x0. |
2929 Label is_number; | 2678 Label is_number; |
2930 __ JumpIfSmi(x0, &is_number); | 2679 __ JumpIfSmi(x0, &is_number); |
2931 | 2680 |
2932 Label not_string; | 2681 Label not_string; |
2933 __ JumpIfObjectType(x0, x1, x1, FIRST_NONSTRING_TYPE, ¬_string, hs); | 2682 __ JumpIfObjectType(x0, x1, x1, FIRST_NONSTRING_TYPE, ¬_string, hs); |
2934 // x0: receiver | 2683 // x0: receiver |
2935 // x1: receiver instance type | 2684 // x1: receiver instance type |
2936 __ Ret(); | 2685 __ Ret(); |
(...skipping 2598 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5535 kStackUnwindSpace, NULL, spill_offset, | 5284 kStackUnwindSpace, NULL, spill_offset, |
5536 return_value_operand, NULL); | 5285 return_value_operand, NULL); |
5537 } | 5286 } |
5538 | 5287 |
5539 #undef __ | 5288 #undef __ |
5540 | 5289 |
5541 } // namespace internal | 5290 } // namespace internal |
5542 } // namespace v8 | 5291 } // namespace v8 |
5543 | 5292 |
5544 #endif // V8_TARGET_ARCH_ARM64 | 5293 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |