OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 | 181 |
182 void RegExpMacroAssemblerX64::CheckCharacterGT(uc16 limit, Label* on_greater) { | 182 void RegExpMacroAssemblerX64::CheckCharacterGT(uc16 limit, Label* on_greater) { |
183 __ cmpl(current_character(), Immediate(limit)); | 183 __ cmpl(current_character(), Immediate(limit)); |
184 BranchOrBacktrack(greater, on_greater); | 184 BranchOrBacktrack(greater, on_greater); |
185 } | 185 } |
186 | 186 |
187 | 187 |
188 void RegExpMacroAssemblerX64::CheckAtStart(Label* on_at_start) { | 188 void RegExpMacroAssemblerX64::CheckAtStart(Label* on_at_start) { |
189 Label not_at_start; | 189 Label not_at_start; |
190 // Did we start the match at the start of the string at all? | 190 // Did we start the match at the start of the string at all? |
191 __ cmpb(Operand(rbp, kAtStart), Immediate(0)); | 191 __ cmpb(Operand(rbp, kStartIndex), Immediate(0)); |
192 BranchOrBacktrack(equal, ¬_at_start); | 192 BranchOrBacktrack(not_equal, ¬_at_start); |
193 // If we did, are we still at the start of the input? | 193 // If we did, are we still at the start of the input? |
194 __ lea(rax, Operand(rsi, rdi, times_1, 0)); | 194 __ lea(rax, Operand(rsi, rdi, times_1, 0)); |
195 __ cmpq(rax, Operand(rbp, kInputStart)); | 195 __ cmpq(rax, Operand(rbp, kInputStart)); |
196 BranchOrBacktrack(equal, on_at_start); | 196 BranchOrBacktrack(equal, on_at_start); |
197 __ bind(¬_at_start); | 197 __ bind(¬_at_start); |
198 } | 198 } |
199 | 199 |
200 | 200 |
201 void RegExpMacroAssemblerX64::CheckNotAtStart(Label* on_not_at_start) { | 201 void RegExpMacroAssemblerX64::CheckNotAtStart(Label* on_not_at_start) { |
202 // Did we start the match at the start of the string at all? | 202 // Did we start the match at the start of the string at all? |
203 __ cmpb(Operand(rbp, kAtStart), Immediate(0)); | 203 __ cmpb(Operand(rbp, kStartIndex), Immediate(0)); |
204 BranchOrBacktrack(equal, on_not_at_start); | 204 BranchOrBacktrack(not_equal, on_not_at_start); |
205 // If we did, are we still at the start of the input? | 205 // If we did, are we still at the start of the input? |
206 __ lea(rax, Operand(rsi, rdi, times_1, 0)); | 206 __ lea(rax, Operand(rsi, rdi, times_1, 0)); |
207 __ cmpq(rax, Operand(rbp, kInputStart)); | 207 __ cmpq(rax, Operand(rbp, kInputStart)); |
208 BranchOrBacktrack(not_equal, on_not_at_start); | 208 BranchOrBacktrack(not_equal, on_not_at_start); |
209 } | 209 } |
210 | 210 |
211 | 211 |
212 void RegExpMacroAssemblerX64::CheckCharacterLT(uc16 limit, Label* on_less) { | 212 void RegExpMacroAssemblerX64::CheckCharacterLT(uc16 limit, Label* on_less) { |
213 __ cmpl(current_character(), Immediate(limit)); | 213 __ cmpl(current_character(), Immediate(limit)); |
214 BranchOrBacktrack(less, on_less); | 214 BranchOrBacktrack(less, on_less); |
215 } | 215 } |
216 | 216 |
217 | 217 |
218 void RegExpMacroAssemblerX64::CheckCharacters(Vector<const uc16> str, | 218 void RegExpMacroAssemblerX64::CheckCharacters(Vector<const uc16> str, |
219 int cp_offset, | 219 int cp_offset, |
220 Label* on_failure, | 220 Label* on_failure, |
221 bool check_end_of_string) { | 221 bool check_end_of_string) { |
| 222 #ifdef DEBUG |
| 223 // If input is ASCII, don't even bother calling here if the string to |
| 224 // match contains a non-ascii character. |
| 225 if (mode_ == ASCII) { |
| 226 for (int i = 0; i < str.length(); i++) { |
| 227 ASSERT(str[i] <= String::kMaxAsciiCharCodeU); |
| 228 } |
| 229 } |
| 230 #endif |
222 int byte_length = str.length() * char_size(); | 231 int byte_length = str.length() * char_size(); |
223 int byte_offset = cp_offset * char_size(); | 232 int byte_offset = cp_offset * char_size(); |
224 if (check_end_of_string) { | 233 if (check_end_of_string) { |
225 // Check that there are at least str.length() characters left in the input. | 234 // Check that there are at least str.length() characters left in the input. |
226 __ cmpl(rdi, Immediate(-(byte_offset + byte_length))); | 235 __ cmpl(rdi, Immediate(-(byte_offset + byte_length))); |
227 BranchOrBacktrack(greater, on_failure); | 236 BranchOrBacktrack(greater, on_failure); |
228 } | 237 } |
229 | 238 |
230 if (on_failure == NULL) { | 239 if (on_failure == NULL) { |
231 // Instead of inlining a backtrack, (re)use the global backtrack target. | 240 // Instead of inlining a backtrack, (re)use the global backtrack target. |
232 on_failure = &backtrack_label_; | 241 on_failure = &backtrack_label_; |
233 } | 242 } |
234 | 243 |
235 // TODO(lrn): Test multiple characters at a time by loading 4 or 8 bytes | 244 // Do one character test first to minimize loading for the case that |
236 // at a time. | 245 // we don't match at all (loading more than one character introduces that |
237 for (int i = 0; i < str.length(); i++) { | 246 // chance of reading unaligned and reading across cache boundaries). |
| 247 // If the first character matches, expect a larger chance of matching the |
| 248 // string, and start loading more characters at a time. |
| 249 if (mode_ == ASCII) { |
| 250 __ cmpb(Operand(rsi, rdi, times_1, byte_offset), |
| 251 Immediate(static_cast<int8_t>(str[0]))); |
| 252 } else { |
| 253 // Don't use 16-bit immediate. The size changing prefix throws off |
| 254 // pre-decoding. |
| 255 __ movzxwl(rax, |
| 256 Operand(rsi, rdi, times_1, byte_offset)); |
| 257 __ cmpl(rax, Immediate(static_cast<int32_t>(str[0]))); |
| 258 } |
| 259 BranchOrBacktrack(not_equal, on_failure); |
| 260 |
| 261 __ lea(rbx, Operand(rsi, rdi, times_1, 0)); |
| 262 for (int i = 1, n = str.length(); i < n; ) { |
238 if (mode_ == ASCII) { | 263 if (mode_ == ASCII) { |
239 __ cmpb(Operand(rsi, rdi, times_1, byte_offset + i), | 264 if (i + 8 <= n) { |
240 Immediate(static_cast<int8_t>(str[i]))); | 265 uint64_t combined_chars = |
| 266 (static_cast<uint64_t>(str[i + 0]) << 0) || |
| 267 (static_cast<uint64_t>(str[i + 1]) << 8) || |
| 268 (static_cast<uint64_t>(str[i + 2]) << 16) || |
| 269 (static_cast<uint64_t>(str[i + 3]) << 24) || |
| 270 (static_cast<uint64_t>(str[i + 4]) << 32) || |
| 271 (static_cast<uint64_t>(str[i + 5]) << 40) || |
| 272 (static_cast<uint64_t>(str[i + 6]) << 48) || |
| 273 (static_cast<uint64_t>(str[i + 7]) << 56); |
| 274 __ movq(rax, combined_chars, RelocInfo::NONE); |
| 275 __ cmpq(rax, Operand(rbx, byte_offset + i)); |
| 276 i += 8; |
| 277 } else if (i + 4 <= n) { |
| 278 uint32_t combined_chars = |
| 279 (static_cast<uint32_t>(str[i + 0]) << 0) || |
| 280 (static_cast<uint32_t>(str[i + 1]) << 8) || |
| 281 (static_cast<uint32_t>(str[i + 2]) << 16) || |
| 282 (static_cast<uint32_t>(str[i + 3]) << 24); |
| 283 __ cmpl(Operand(rbx, byte_offset + i), Immediate(combined_chars)); |
| 284 i += 4; |
| 285 } else { |
| 286 __ cmpb(Operand(rbx, byte_offset + i), |
| 287 Immediate(static_cast<int8_t>(str[i]))); |
| 288 i++; |
| 289 } |
241 } else { | 290 } else { |
242 ASSERT(mode_ == UC16); | 291 ASSERT(mode_ == UC16); |
243 __ cmpw(Operand(rsi, rdi, times_1, byte_offset + i * sizeof(uc16)), | 292 if (i + 4 <= n) { |
244 Immediate(str[i])); | 293 uint64_t combined_chars = *reinterpret_cast<const uint64_t*>(&str[i]); |
| 294 __ movq(rax, combined_chars, RelocInfo::NONE); |
| 295 __ cmpq(rax, |
| 296 Operand(rsi, rdi, times_1, byte_offset + i * sizeof(uc16))); |
| 297 i += 4; |
| 298 } else if (i + 2 <= n) { |
| 299 uint32_t combined_chars = *reinterpret_cast<const uint32_t*>(&str[i]); |
| 300 __ cmpl(Operand(rsi, rdi, times_1, byte_offset + i * sizeof(uc16)), |
| 301 Immediate(combined_chars)); |
| 302 i += 2; |
| 303 } else { |
| 304 __ movzxwl(rax, |
| 305 Operand(rsi, rdi, times_1, byte_offset + i * sizeof(uc16))); |
| 306 __ cmpl(rax, Immediate(str[i])); |
| 307 i++; |
| 308 } |
245 } | 309 } |
246 BranchOrBacktrack(not_equal, on_failure); | 310 BranchOrBacktrack(not_equal, on_failure); |
247 } | 311 } |
248 } | 312 } |
249 | 313 |
250 | 314 |
251 void RegExpMacroAssemblerX64::CheckGreedyLoop(Label* on_equal) { | 315 void RegExpMacroAssemblerX64::CheckGreedyLoop(Label* on_equal) { |
252 Label fallthrough; | 316 Label fallthrough; |
253 __ cmpl(rdi, Operand(backtrack_stackpointer(), 0)); | 317 __ cmpl(rdi, Operand(backtrack_stackpointer(), 0)); |
254 __ j(not_equal, &fallthrough); | 318 __ j(not_equal, &fallthrough); |
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
664 __ push(rdi); | 728 __ push(rdi); |
665 __ push(rsi); | 729 __ push(rsi); |
666 __ push(rdx); | 730 __ push(rdx); |
667 __ push(rcx); | 731 __ push(rcx); |
668 __ push(r8); | 732 __ push(r8); |
669 __ push(r9); | 733 __ push(r9); |
670 | 734 |
671 __ push(rbx); // Callee-save | 735 __ push(rbx); // Callee-save |
672 #endif | 736 #endif |
673 | 737 |
674 __ push(Immediate(0)); // Make room for "input start - 1" constant. | |
675 __ push(Immediate(0)); // Make room for "at start" constant. | 738 __ push(Immediate(0)); // Make room for "at start" constant. |
676 | 739 |
677 // Check if we have space on the stack for registers. | 740 // Check if we have space on the stack for registers. |
678 Label stack_limit_hit; | 741 Label stack_limit_hit; |
679 Label stack_ok; | 742 Label stack_ok; |
680 | 743 |
681 ExternalReference stack_limit = | 744 ExternalReference stack_limit = |
682 ExternalReference::address_of_stack_limit(); | 745 ExternalReference::address_of_stack_limit(); |
683 __ movq(rcx, rsp); | 746 __ movq(rcx, rsp); |
684 __ movq(kScratchRegister, stack_limit); | 747 __ movq(kScratchRegister, stack_limit); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 __ neg(rbx); | 780 __ neg(rbx); |
718 if (mode_ == UC16) { | 781 if (mode_ == UC16) { |
719 __ lea(rax, Operand(rdi, rbx, times_2, -char_size())); | 782 __ lea(rax, Operand(rdi, rbx, times_2, -char_size())); |
720 } else { | 783 } else { |
721 __ lea(rax, Operand(rdi, rbx, times_1, -char_size())); | 784 __ lea(rax, Operand(rdi, rbx, times_1, -char_size())); |
722 } | 785 } |
723 // Store this value in a local variable, for use when clearing | 786 // Store this value in a local variable, for use when clearing |
724 // position registers. | 787 // position registers. |
725 __ movq(Operand(rbp, kInputStartMinusOne), rax); | 788 __ movq(Operand(rbp, kInputStartMinusOne), rax); |
726 | 789 |
727 // Determine whether the start index is zero, that is at the start of the | |
728 // string, and store that value in a local variable. | |
729 __ movq(rbx, Operand(rbp, kStartIndex)); | |
730 __ xor_(rcx, rcx); // setcc only operates on cl (lower byte of rcx). | |
731 __ testq(rbx, rbx); | |
732 __ setcc(zero, rcx); // 1 if 0 (start of string), 0 if positive. | |
733 __ movq(Operand(rbp, kAtStart), rcx); | |
734 | |
735 if (num_saved_registers_ > 0) { | 790 if (num_saved_registers_ > 0) { |
736 // Fill saved registers with initial value = start offset - 1 | 791 // Fill saved registers with initial value = start offset - 1 |
737 // Fill in stack push order, to avoid accessing across an unwritten | 792 // Fill in stack push order, to avoid accessing across an unwritten |
738 // page (a problem on Windows). | 793 // page (a problem on Windows). |
739 __ movq(rcx, Immediate(kRegisterZero)); | 794 __ movq(rcx, Immediate(kRegisterZero)); |
740 Label init_loop; | 795 Label init_loop; |
741 __ bind(&init_loop); | 796 __ bind(&init_loop); |
742 __ movq(Operand(rbp, rcx, times_1, 0), rax); | 797 __ movq(Operand(rbp, rcx, times_1, 0), rax); |
743 __ subq(rcx, Immediate(kPointerSize)); | 798 __ subq(rcx, Immediate(kPointerSize)); |
744 __ cmpq(rcx, | 799 __ cmpq(rcx, |
745 Immediate(kRegisterZero - num_saved_registers_ * kPointerSize)); | 800 Immediate(kRegisterZero - num_saved_registers_ * kPointerSize)); |
746 __ j(greater, &init_loop); | 801 __ j(greater, &init_loop); |
747 } | 802 } |
748 // Ensure that we have written to each stack page, in order. Skipping a page | 803 // Ensure that we have written to each stack page, in order. Skipping a page |
749 // on Windows can cause segmentation faults. Assuming page size is 4k. | 804 // on Windows can cause segmentation faults. Assuming page size is 4k. |
750 const int kPageSize = 4096; | 805 const int kPageSize = 4096; |
751 const int kRegistersPerPage = kPageSize / kPointerSize; | 806 const int kRegistersPerPage = kPageSize / kPointerSize; |
752 for (int i = num_saved_registers_ + kRegistersPerPage - 1; | 807 for (int i = num_saved_registers_ + kRegistersPerPage - 1; |
753 i < num_registers_; | 808 i < num_registers_; |
754 i += kRegistersPerPage) { | 809 i += kRegistersPerPage) { |
755 __ movq(register_location(i), rax); // One write every page. | 810 __ movq(register_location(i), rax); // One write every page. |
756 } | 811 } |
757 | 812 |
758 // Initialize backtrack stack pointer. | 813 // Initialize backtrack stack pointer. |
759 __ movq(backtrack_stackpointer(), Operand(rbp, kStackHighEnd)); | 814 __ movq(backtrack_stackpointer(), Operand(rbp, kStackHighEnd)); |
760 // Initialize code object pointer. | 815 // Initialize code object pointer. |
761 __ Move(code_object_pointer(), masm_->CodeObject()); | 816 __ Move(code_object_pointer(), masm_->CodeObject()); |
762 // Load previous char as initial value of current-character. | 817 // Load previous char as initial value of current-character. |
763 Label at_start; | 818 Label at_start; |
764 __ cmpb(Operand(rbp, kAtStart), Immediate(0)); | 819 __ cmpb(Operand(rbp, kStartIndex), Immediate(0)); |
765 __ j(not_equal, &at_start); | 820 __ j(equal, &at_start); |
766 LoadCurrentCharacterUnchecked(-1, 1); // Load previous char. | 821 LoadCurrentCharacterUnchecked(-1, 1); // Load previous char. |
767 __ jmp(&start_label_); | 822 __ jmp(&start_label_); |
768 __ bind(&at_start); | 823 __ bind(&at_start); |
769 __ movq(current_character(), Immediate('\n')); | 824 __ movq(current_character(), Immediate('\n')); |
770 __ jmp(&start_label_); | 825 __ jmp(&start_label_); |
771 | 826 |
772 | 827 |
773 // Exit code: | 828 // Exit code: |
774 if (success_label_.is_linked()) { | 829 if (success_label_.is_linked()) { |
775 // Save captures when successful. | 830 // Save captures when successful. |
(...skipping 530 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1306 Operand(rsi, rdi, times_1, cp_offset * sizeof(uc16))); | 1361 Operand(rsi, rdi, times_1, cp_offset * sizeof(uc16))); |
1307 } | 1362 } |
1308 } | 1363 } |
1309 } | 1364 } |
1310 | 1365 |
1311 #undef __ | 1366 #undef __ |
1312 | 1367 |
1313 #endif // V8_INTERPRETED_REGEXP | 1368 #endif // V8_INTERPRETED_REGEXP |
1314 | 1369 |
1315 }} // namespace v8::internal | 1370 }} // namespace v8::internal |
OLD | NEW |