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 |
2676 void ToStringStub::Generate(MacroAssembler* masm) { | 2927 void ToStringStub::Generate(MacroAssembler* masm) { |
2677 // The ToString stub takes one argument in x0. | 2928 // The ToString stub takes one argument in x0. |
2678 Label is_number; | 2929 Label is_number; |
2679 __ JumpIfSmi(x0, &is_number); | 2930 __ JumpIfSmi(x0, &is_number); |
2680 | 2931 |
2681 Label not_string; | 2932 Label not_string; |
2682 __ JumpIfObjectType(x0, x1, x1, FIRST_NONSTRING_TYPE, ¬_string, hs); | 2933 __ JumpIfObjectType(x0, x1, x1, FIRST_NONSTRING_TYPE, ¬_string, hs); |
2683 // x0: receiver | 2934 // x0: receiver |
2684 // x1: receiver instance type | 2935 // x1: receiver instance type |
2685 __ Ret(); | 2936 __ Ret(); |
(...skipping 2598 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5284 kStackUnwindSpace, NULL, spill_offset, | 5535 kStackUnwindSpace, NULL, spill_offset, |
5285 return_value_operand, NULL); | 5536 return_value_operand, NULL); |
5286 } | 5537 } |
5287 | 5538 |
5288 #undef __ | 5539 #undef __ |
5289 | 5540 |
5290 } // namespace internal | 5541 } // namespace internal |
5291 } // namespace v8 | 5542 } // namespace v8 |
5292 | 5543 |
5293 #endif // V8_TARGET_ARCH_ARM64 | 5544 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |