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 |
2014 void ToStringStub::Generate(MacroAssembler* masm) { | 2235 void ToStringStub::Generate(MacroAssembler* masm) { |
2015 // The ToString stub takes one argument in rax. | 2236 // The ToString stub takes one argument in rax. |
2016 Label is_number; | 2237 Label is_number; |
2017 __ JumpIfSmi(rax, &is_number, Label::kNear); | 2238 __ JumpIfSmi(rax, &is_number, Label::kNear); |
2018 | 2239 |
2019 Label not_string; | 2240 Label not_string; |
2020 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdi); | 2241 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdi); |
2021 // rax: receiver | 2242 // rax: receiver |
2022 // rdi: receiver map | 2243 // rdi: receiver map |
2023 __ j(above_equal, ¬_string, Label::kNear); | 2244 __ j(above_equal, ¬_string, Label::kNear); |
(...skipping 2916 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4940 kStackUnwindSpace, nullptr, return_value_operand, | 5161 kStackUnwindSpace, nullptr, return_value_operand, |
4941 NULL); | 5162 NULL); |
4942 } | 5163 } |
4943 | 5164 |
4944 #undef __ | 5165 #undef __ |
4945 | 5166 |
4946 } // namespace internal | 5167 } // namespace internal |
4947 } // namespace v8 | 5168 } // namespace v8 |
4948 | 5169 |
4949 #endif // V8_TARGET_ARCH_X64 | 5170 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |