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_X64 | 5 #if V8_TARGET_ARCH_X64 |
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 1993 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2004 __ movb(kScratchRegister, Operand(src, 0)); | 2004 __ movb(kScratchRegister, Operand(src, 0)); |
2005 __ movb(Operand(dest, 0), kScratchRegister); | 2005 __ movb(Operand(dest, 0), kScratchRegister); |
2006 __ incp(src); | 2006 __ incp(src); |
2007 __ incp(dest); | 2007 __ incp(dest); |
2008 __ decl(count); | 2008 __ decl(count); |
2009 __ j(not_zero, &loop); | 2009 __ j(not_zero, &loop); |
2010 | 2010 |
2011 __ bind(&done); | 2011 __ bind(&done); |
2012 } | 2012 } |
2013 | 2013 |
2014 | |
2015 void SubStringStub::Generate(MacroAssembler* masm) { | |
2016 Label runtime; | |
2017 | |
2018 // Stack frame on entry. | |
2019 // rsp[0] : return address | |
2020 // rsp[8] : to | |
2021 // rsp[16] : from | |
2022 // rsp[24] : string | |
2023 | |
2024 enum SubStringStubArgumentIndices { | |
2025 STRING_ARGUMENT_INDEX, | |
2026 FROM_ARGUMENT_INDEX, | |
2027 TO_ARGUMENT_INDEX, | |
2028 SUB_STRING_ARGUMENT_COUNT | |
2029 }; | |
2030 | |
2031 StackArgumentsAccessor args(rsp, SUB_STRING_ARGUMENT_COUNT, | |
2032 ARGUMENTS_DONT_CONTAIN_RECEIVER); | |
2033 | |
2034 // Make sure first argument is a string. | |
2035 __ movp(rax, args.GetArgumentOperand(STRING_ARGUMENT_INDEX)); | |
2036 STATIC_ASSERT(kSmiTag == 0); | |
2037 __ testl(rax, Immediate(kSmiTagMask)); | |
2038 __ j(zero, &runtime); | |
2039 Condition is_string = masm->IsObjectStringType(rax, rbx, rbx); | |
2040 __ j(NegateCondition(is_string), &runtime); | |
2041 | |
2042 // rax: string | |
2043 // rbx: instance type | |
2044 // Calculate length of sub string using the smi values. | |
2045 __ movp(rcx, args.GetArgumentOperand(TO_ARGUMENT_INDEX)); | |
2046 __ movp(rdx, args.GetArgumentOperand(FROM_ARGUMENT_INDEX)); | |
2047 __ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime); | |
2048 | |
2049 __ SmiSub(rcx, rcx, rdx); // Overflow doesn't happen. | |
2050 __ cmpp(rcx, FieldOperand(rax, String::kLengthOffset)); | |
2051 Label not_original_string; | |
2052 // Shorter than original string's length: an actual substring. | |
2053 __ j(below, ¬_original_string, Label::kNear); | |
2054 // Longer than original string's length or negative: unsafe arguments. | |
2055 __ j(above, &runtime); | |
2056 // Return original string. | |
2057 Counters* counters = isolate()->counters(); | |
2058 __ IncrementCounter(counters->sub_string_native(), 1); | |
2059 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); | |
2060 __ bind(¬_original_string); | |
2061 | |
2062 Label single_char; | |
2063 __ SmiCompare(rcx, Smi::FromInt(1)); | |
2064 __ j(equal, &single_char); | |
2065 | |
2066 __ SmiToInteger32(rcx, rcx); | |
2067 | |
2068 // rax: string | |
2069 // rbx: instance type | |
2070 // rcx: sub string length | |
2071 // rdx: from index (smi) | |
2072 // Deal with different string types: update the index if necessary | |
2073 // and put the underlying string into edi. | |
2074 Label underlying_unpacked, sliced_string, seq_or_external_string; | |
2075 // If the string is not indirect, it can only be sequential or external. | |
2076 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); | |
2077 STATIC_ASSERT(kIsIndirectStringMask != 0); | |
2078 __ testb(rbx, Immediate(kIsIndirectStringMask)); | |
2079 __ j(zero, &seq_or_external_string, Label::kNear); | |
2080 | |
2081 __ testb(rbx, Immediate(kSlicedNotConsMask)); | |
2082 __ j(not_zero, &sliced_string, Label::kNear); | |
2083 // Cons string. Check whether it is flat, then fetch first part. | |
2084 // Flat cons strings have an empty second part. | |
2085 __ CompareRoot(FieldOperand(rax, ConsString::kSecondOffset), | |
2086 Heap::kempty_stringRootIndex); | |
2087 __ j(not_equal, &runtime); | |
2088 __ movp(rdi, FieldOperand(rax, ConsString::kFirstOffset)); | |
2089 // Update instance type. | |
2090 __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | |
2091 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | |
2092 __ jmp(&underlying_unpacked, Label::kNear); | |
2093 | |
2094 __ bind(&sliced_string); | |
2095 // Sliced string. Fetch parent and correct start index by offset. | |
2096 __ addp(rdx, FieldOperand(rax, SlicedString::kOffsetOffset)); | |
2097 __ movp(rdi, FieldOperand(rax, SlicedString::kParentOffset)); | |
2098 // Update instance type. | |
2099 __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | |
2100 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | |
2101 __ jmp(&underlying_unpacked, Label::kNear); | |
2102 | |
2103 __ bind(&seq_or_external_string); | |
2104 // Sequential or external string. Just move string to the correct register. | |
2105 __ movp(rdi, rax); | |
2106 | |
2107 __ bind(&underlying_unpacked); | |
2108 | |
2109 if (FLAG_string_slices) { | |
2110 Label copy_routine; | |
2111 // rdi: underlying subject string | |
2112 // rbx: instance type of underlying subject string | |
2113 // rdx: adjusted start index (smi) | |
2114 // rcx: length | |
2115 // If coming from the make_two_character_string path, the string | |
2116 // is too short to be sliced anyways. | |
2117 __ cmpp(rcx, Immediate(SlicedString::kMinLength)); | |
2118 // Short slice. Copy instead of slicing. | |
2119 __ j(less, ©_routine); | |
2120 // Allocate new sliced string. At this point we do not reload the instance | |
2121 // type including the string encoding because we simply rely on the info | |
2122 // provided by the original string. It does not matter if the original | |
2123 // string's encoding is wrong because we always have to recheck encoding of | |
2124 // the newly created string's parent anyways due to externalized strings. | |
2125 Label two_byte_slice, set_slice_header; | |
2126 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); | |
2127 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | |
2128 __ testb(rbx, Immediate(kStringEncodingMask)); | |
2129 __ j(zero, &two_byte_slice, Label::kNear); | |
2130 __ AllocateOneByteSlicedString(rax, rbx, r14, &runtime); | |
2131 __ jmp(&set_slice_header, Label::kNear); | |
2132 __ bind(&two_byte_slice); | |
2133 __ AllocateTwoByteSlicedString(rax, rbx, r14, &runtime); | |
2134 __ bind(&set_slice_header); | |
2135 __ Integer32ToSmi(rcx, rcx); | |
2136 __ movp(FieldOperand(rax, SlicedString::kLengthOffset), rcx); | |
2137 __ movp(FieldOperand(rax, SlicedString::kHashFieldOffset), | |
2138 Immediate(String::kEmptyHashField)); | |
2139 __ movp(FieldOperand(rax, SlicedString::kParentOffset), rdi); | |
2140 __ movp(FieldOperand(rax, SlicedString::kOffsetOffset), rdx); | |
2141 __ IncrementCounter(counters->sub_string_native(), 1); | |
2142 __ ret(3 * kPointerSize); | |
2143 | |
2144 __ bind(©_routine); | |
2145 } | |
2146 | |
2147 // rdi: underlying subject string | |
2148 // rbx: instance type of underlying subject string | |
2149 // rdx: adjusted start index (smi) | |
2150 // rcx: length | |
2151 // The subject string can only be external or sequential string of either | |
2152 // encoding at this point. | |
2153 Label two_byte_sequential, sequential_string; | |
2154 STATIC_ASSERT(kExternalStringTag != 0); | |
2155 STATIC_ASSERT(kSeqStringTag == 0); | |
2156 __ testb(rbx, Immediate(kExternalStringTag)); | |
2157 __ j(zero, &sequential_string); | |
2158 | |
2159 // Handle external string. | |
2160 // Rule out short external strings. | |
2161 STATIC_ASSERT(kShortExternalStringTag != 0); | |
2162 __ testb(rbx, Immediate(kShortExternalStringMask)); | |
2163 __ j(not_zero, &runtime); | |
2164 __ movp(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); | |
2165 // Move the pointer so that offset-wise, it looks like a sequential string. | |
2166 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | |
2167 __ subp(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
2168 | |
2169 __ bind(&sequential_string); | |
2170 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); | |
2171 __ testb(rbx, Immediate(kStringEncodingMask)); | |
2172 __ j(zero, &two_byte_sequential); | |
2173 | |
2174 // Allocate the result. | |
2175 __ AllocateOneByteString(rax, rcx, r11, r14, r15, &runtime); | |
2176 | |
2177 // rax: result string | |
2178 // rcx: result string length | |
2179 { // Locate character of sub string start. | |
2180 SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_1); | |
2181 __ leap(r14, Operand(rdi, smi_as_index.reg, smi_as_index.scale, | |
2182 SeqOneByteString::kHeaderSize - kHeapObjectTag)); | |
2183 } | |
2184 // Locate first character of result. | |
2185 __ leap(rdi, FieldOperand(rax, SeqOneByteString::kHeaderSize)); | |
2186 | |
2187 // rax: result string | |
2188 // rcx: result length | |
2189 // r14: first character of result | |
2190 // rsi: character of sub string start | |
2191 StringHelper::GenerateCopyCharacters( | |
2192 masm, rdi, r14, rcx, String::ONE_BYTE_ENCODING); | |
2193 __ IncrementCounter(counters->sub_string_native(), 1); | |
2194 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); | |
2195 | |
2196 __ bind(&two_byte_sequential); | |
2197 // Allocate the result. | |
2198 __ AllocateTwoByteString(rax, rcx, r11, r14, r15, &runtime); | |
2199 | |
2200 // rax: result string | |
2201 // rcx: result string length | |
2202 { // Locate character of sub string start. | |
2203 SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_2); | |
2204 __ leap(r14, Operand(rdi, smi_as_index.reg, smi_as_index.scale, | |
2205 SeqOneByteString::kHeaderSize - kHeapObjectTag)); | |
2206 } | |
2207 // Locate first character of result. | |
2208 __ leap(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); | |
2209 | |
2210 // rax: result string | |
2211 // rcx: result length | |
2212 // rdi: first character of result | |
2213 // r14: character of sub string start | |
2214 StringHelper::GenerateCopyCharacters( | |
2215 masm, rdi, r14, rcx, String::TWO_BYTE_ENCODING); | |
2216 __ IncrementCounter(counters->sub_string_native(), 1); | |
2217 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); | |
2218 | |
2219 // Just jump to runtime to create the sub string. | |
2220 __ bind(&runtime); | |
2221 __ TailCallRuntime(Runtime::kSubString); | |
2222 | |
2223 __ bind(&single_char); | |
2224 // rax: string | |
2225 // rbx: instance type | |
2226 // rcx: sub string length (smi) | |
2227 // rdx: from index (smi) | |
2228 StringCharAtGenerator generator(rax, rdx, rcx, rax, &runtime, &runtime, | |
2229 &runtime, RECEIVER_IS_STRING); | |
2230 generator.GenerateFast(masm); | |
2231 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); | |
2232 generator.SkipSlow(masm, &runtime); | |
2233 } | |
2234 | |
2235 void ToStringStub::Generate(MacroAssembler* masm) { | 2014 void ToStringStub::Generate(MacroAssembler* masm) { |
2236 // The ToString stub takes one argument in rax. | 2015 // The ToString stub takes one argument in rax. |
2237 Label is_number; | 2016 Label is_number; |
2238 __ JumpIfSmi(rax, &is_number, Label::kNear); | 2017 __ JumpIfSmi(rax, &is_number, Label::kNear); |
2239 | 2018 |
2240 Label not_string; | 2019 Label not_string; |
2241 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdi); | 2020 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdi); |
2242 // rax: receiver | 2021 // rax: receiver |
2243 // rdi: receiver map | 2022 // rdi: receiver map |
2244 __ j(above_equal, ¬_string, Label::kNear); | 2023 __ j(above_equal, ¬_string, Label::kNear); |
(...skipping 2905 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5150 kStackUnwindSpace, nullptr, return_value_operand, | 4929 kStackUnwindSpace, nullptr, return_value_operand, |
5151 NULL); | 4930 NULL); |
5152 } | 4931 } |
5153 | 4932 |
5154 #undef __ | 4933 #undef __ |
5155 | 4934 |
5156 } // namespace internal | 4935 } // namespace internal |
5157 } // namespace v8 | 4936 } // namespace v8 |
5158 | 4937 |
5159 #endif // V8_TARGET_ARCH_X64 | 4938 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |