| 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 2916 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5161 kStackUnwindSpace, nullptr, return_value_operand, | 4940 kStackUnwindSpace, nullptr, return_value_operand, |
| 5162 NULL); | 4941 NULL); |
| 5163 } | 4942 } |
| 5164 | 4943 |
| 5165 #undef __ | 4944 #undef __ |
| 5166 | 4945 |
| 5167 } // namespace internal | 4946 } // namespace internal |
| 5168 } // namespace v8 | 4947 } // namespace v8 |
| 5169 | 4948 |
| 5170 #endif // V8_TARGET_ARCH_X64 | 4949 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |