5 #if V8_TARGET_ARCH_ARM64 7 #include "src/regexp/arm64/regexp-macro-assembler-arm64.h" 9 #include "src/arm64/macro-assembler-arm64-inl.h" 10 #include "src/code-stubs.h" 12 #include "src/macro-assembler.h" 13 #include "src/objects-inl.h" 14 #include "src/regexp/regexp-macro-assembler.h" 15 #include "src/regexp/regexp-stack.h" 21 #ifndef V8_INTERPRETED_REGEXP 102 #define __ ACCESS_MASM(masm_) 104 RegExpMacroAssemblerARM64::RegExpMacroAssemblerARM64(Isolate* isolate,
105 Zone* zone, Mode mode,
106 int registers_to_save)
107 : NativeRegExpMacroAssembler(isolate, zone),
108 masm_(new MacroAssembler(isolate, nullptr, kRegExpCodeSize,
109 CodeObjectRequired::kYes)),
111 num_registers_(registers_to_save),
112 num_saved_registers_(registers_to_save),
118 DCHECK_EQ(0, registers_to_save % 2);
120 STATIC_ASSERT(kNumCachedRegisters <= 16);
121 STATIC_ASSERT((kNumCachedRegisters % 2) == 0);
123 __ Bind(&start_label_);
127 RegExpMacroAssemblerARM64::~RegExpMacroAssemblerARM64() {
130 entry_label_.Unuse();
131 start_label_.Unuse();
132 success_label_.Unuse();
133 backtrack_label_.Unuse();
135 check_preempt_label_.Unuse();
136 stack_overflow_label_.Unuse();
139 int RegExpMacroAssemblerARM64::stack_limit_slack() {
140 return RegExpStack::kStackLimitSlack;
144 void RegExpMacroAssemblerARM64::AdvanceCurrentPosition(
int by) {
146 __ Add(current_input_offset(),
147 current_input_offset(), by * char_size());
152 void RegExpMacroAssemblerARM64::AdvanceRegister(
int reg,
int by) {
153 DCHECK((reg >= 0) && (reg < num_registers_));
155 RegisterState register_state = GetRegisterState(reg);
156 switch (register_state) {
158 __ Ldr(w10, register_location(reg));
159 __ Add(w10, w10, by);
160 __ Str(w10, register_location(reg));
163 Register to_advance = GetCachedRegister(reg);
164 __ Add(to_advance, to_advance, by);
168 Register to_advance = GetCachedRegister(reg);
169 __ Add(to_advance, to_advance,
170 static_cast<int64_t>(by) << kWRegSizeInBits);
181 void RegExpMacroAssemblerARM64::Backtrack() {
184 __ Add(x10, code_pointer(), Operand(w10, UXTW));
189 void RegExpMacroAssemblerARM64::Bind(Label* label) {
194 void RegExpMacroAssemblerARM64::CheckCharacter(
uint32_t c, Label* on_equal) {
195 CompareAndBranchOrBacktrack(current_character(), c, eq, on_equal);
199 void RegExpMacroAssemblerARM64::CheckCharacterGT(uc16 limit,
201 CompareAndBranchOrBacktrack(current_character(), limit, hi, on_greater);
205 void RegExpMacroAssemblerARM64::CheckAtStart(Label* on_at_start) {
206 __ Add(w10, current_input_offset(), Operand(-char_size()));
207 __ Cmp(w10, string_start_minus_one());
208 BranchOrBacktrack(eq, on_at_start);
212 void RegExpMacroAssemblerARM64::CheckNotAtStart(
int cp_offset,
213 Label* on_not_at_start) {
214 __ Add(w10, current_input_offset(),
215 Operand(-char_size() + cp_offset * char_size()));
216 __ Cmp(w10, string_start_minus_one());
217 BranchOrBacktrack(ne, on_not_at_start);
221 void RegExpMacroAssemblerARM64::CheckCharacterLT(uc16 limit, Label* on_less) {
222 CompareAndBranchOrBacktrack(current_character(), limit, lo, on_less);
226 void RegExpMacroAssemblerARM64::CheckCharacters(Vector<const uc16> str,
229 bool check_end_of_string) {
232 if (check_end_of_string) {
234 CheckPosition(cp_offset + str.length() - 1, on_failure);
237 Register characters_address = x11;
239 __ Add(characters_address,
241 Operand(current_input_offset(), SXTW));
242 if (cp_offset != 0) {
243 __ Add(characters_address, characters_address, cp_offset * char_size());
246 for (
int i = 0;
i < str.length();
i++) {
247 if (mode_ == LATIN1) {
248 __ Ldrb(w10, MemOperand(characters_address, 1, PostIndex));
249 DCHECK_GE(String::kMaxOneByteCharCode, str[
i]);
251 __ Ldrh(w10, MemOperand(characters_address, 2, PostIndex));
253 CompareAndBranchOrBacktrack(w10, str[
i], ne, on_failure);
258 void RegExpMacroAssemblerARM64::CheckGreedyLoop(Label* on_equal) {
259 __ Ldr(w10, MemOperand(backtrack_stackpointer()));
260 __ Cmp(current_input_offset(), w10);
262 __ Add(backtrack_stackpointer(),
263 backtrack_stackpointer(), Operand(x11, LSL, kWRegSizeLog2));
264 BranchOrBacktrack(eq, on_equal);
268 void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase(
269 int start_reg,
bool read_backward,
bool unicode, Label* on_no_match) {
272 Register capture_start_offset = w10;
275 Register capture_length = w19;
276 DCHECK(kCalleeSaved.IncludesAliasOf(capture_length));
279 DCHECK_EQ(0, start_reg % 2);
280 if (start_reg < kNumCachedRegisters) {
281 __ Mov(capture_start_offset.X(), GetCachedRegister(start_reg));
282 __ Lsr(x11, GetCachedRegister(start_reg), kWRegSizeInBits);
284 __ Ldp(w11, capture_start_offset, capture_location(start_reg, x10));
286 __ Sub(capture_length, w11, capture_start_offset);
291 __ CompareAndBranch(capture_length, Operand(0), eq, &fallthrough);
295 __ Add(w12, string_start_minus_one(), capture_length);
296 __ Cmp(current_input_offset(), w12);
297 BranchOrBacktrack(le, on_no_match);
299 __ Cmn(capture_length, current_input_offset());
300 BranchOrBacktrack(gt, on_no_match);
303 if (mode_ == LATIN1) {
308 Register capture_start_address = x12;
309 Register capture_end_addresss = x13;
310 Register current_position_address = x14;
312 __ Add(capture_start_address,
314 Operand(capture_start_offset, SXTW));
315 __ Add(capture_end_addresss,
316 capture_start_address,
317 Operand(capture_length, SXTW));
318 __ Add(current_position_address,
320 Operand(current_input_offset(), SXTW));
323 __ Sub(current_position_address, current_position_address,
324 Operand(capture_length, SXTW));
329 __ Ldrb(w10, MemOperand(capture_start_address, 1, PostIndex));
330 __ Ldrb(w11, MemOperand(current_position_address, 1, PostIndex));
332 __ B(eq, &loop_check);
335 __ Orr(w10, w10, 0x20);
336 __ Orr(w11, w11, 0x20);
339 __ Sub(w10, w10,
'a');
340 __ Cmp(w10,
'z' -
'a');
341 __ B(ls, &loop_check);
343 __ Sub(w10, w10, 224 -
'a');
344 __ Cmp(w10, 254 - 224);
345 __ Ccmp(w10, 247 - 224, ZFlag, ls);
348 __ Bind(&loop_check);
349 __ Cmp(capture_start_address, capture_end_addresss);
354 BranchOrBacktrack(al, on_no_match);
358 __ Sub(current_input_offset().X(), current_position_address, input_end());
360 __ Sub(current_input_offset().X(), current_input_offset().X(),
361 Operand(capture_length, SXTW));
363 if (masm_->emit_debug_code()) {
364 __ Cmp(current_input_offset().X(), Operand(current_input_offset(), SXTW));
365 __ Ccmp(current_input_offset(), 0, NoFlag, eq);
367 __ Check(le, AbortReason::kOffsetOutOfRange);
370 DCHECK(mode_ == UC16);
371 int argument_count = 4;
374 CPURegList cached_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 7);
375 DCHECK_EQ(kNumCachedRegisters, cached_registers.Count() * 2);
376 __ PushCPURegList(cached_registers);
386 __ Add(x0, input_end(), Operand(capture_start_offset, SXTW));
388 __ Mov(w2, capture_length);
390 __ Add(x1, input_end(), Operand(current_input_offset(), SXTW));
392 __ Sub(x1, x1, Operand(capture_length, SXTW));
395 #ifdef V8_INTL_SUPPORT 397 __ Mov(x3, Operand(0));
399 #endif // V8_INTL_SUPPORT 401 __ Mov(x3, ExternalReference::isolate_address(isolate()));
405 AllowExternalCallThatCantCauseGC scope(masm_);
406 ExternalReference
function =
407 ExternalReference::re_case_insensitive_compare_uc16(isolate());
408 __ CallCFunction(
function, argument_count);
415 __ PopCPURegList(cached_registers);
416 BranchOrBacktrack(eq, on_no_match);
420 __ Sub(current_input_offset(), current_input_offset(), capture_length);
422 __ Add(current_input_offset(), current_input_offset(), capture_length);
426 __ Bind(&fallthrough);
429 void RegExpMacroAssemblerARM64::CheckNotBackReference(
int start_reg,
431 Label* on_no_match) {
434 Register capture_start_address = x12;
435 Register capture_end_address = x13;
436 Register current_position_address = x14;
437 Register capture_length = w15;
440 DCHECK_EQ(0, start_reg % 2);
441 if (start_reg < kNumCachedRegisters) {
442 __ Mov(x10, GetCachedRegister(start_reg));
443 __ Lsr(x11, GetCachedRegister(start_reg), kWRegSizeInBits);
445 __ Ldp(w11, w10, capture_location(start_reg, x10));
447 __ Sub(capture_length, w11, w10);
452 __ CompareAndBranch(capture_length, Operand(0), eq, &fallthrough);
456 __ Add(w12, string_start_minus_one(), capture_length);
457 __ Cmp(current_input_offset(), w12);
458 BranchOrBacktrack(le, on_no_match);
460 __ Cmn(capture_length, current_input_offset());
461 BranchOrBacktrack(gt, on_no_match);
465 __ Add(capture_start_address, input_end(), Operand(w10, SXTW));
466 __ Add(capture_end_address,
467 capture_start_address,
468 Operand(capture_length, SXTW));
469 __ Add(current_position_address,
471 Operand(current_input_offset(), SXTW));
474 __ Sub(current_position_address, current_position_address,
475 Operand(capture_length, SXTW));
480 if (mode_ == LATIN1) {
481 __ Ldrb(w10, MemOperand(capture_start_address, 1, PostIndex));
482 __ Ldrb(w11, MemOperand(current_position_address, 1, PostIndex));
484 DCHECK(mode_ == UC16);
485 __ Ldrh(w10, MemOperand(capture_start_address, 2, PostIndex));
486 __ Ldrh(w11, MemOperand(current_position_address, 2, PostIndex));
489 BranchOrBacktrack(ne, on_no_match);
490 __ Cmp(capture_start_address, capture_end_address);
494 __ Sub(current_input_offset().X(), current_position_address, input_end());
496 __ Sub(current_input_offset().X(), current_input_offset().X(),
497 Operand(capture_length, SXTW));
500 if (masm_->emit_debug_code()) {
501 __ Cmp(current_input_offset().X(), Operand(current_input_offset(), SXTW));
502 __ Ccmp(current_input_offset(), 0, NoFlag, eq);
504 __ Check(le, AbortReason::kOffsetOutOfRange);
506 __ Bind(&fallthrough);
510 void RegExpMacroAssemblerARM64::CheckNotCharacter(
unsigned c,
511 Label* on_not_equal) {
512 CompareAndBranchOrBacktrack(current_character(), c, ne, on_not_equal);
516 void RegExpMacroAssemblerARM64::CheckCharacterAfterAnd(
uint32_t c,
519 __ And(w10, current_character(), mask);
520 CompareAndBranchOrBacktrack(w10, c, eq, on_equal);
524 void RegExpMacroAssemblerARM64::CheckNotCharacterAfterAnd(
unsigned c,
526 Label* on_not_equal) {
527 __ And(w10, current_character(), mask);
528 CompareAndBranchOrBacktrack(w10, c, ne, on_not_equal);
532 void RegExpMacroAssemblerARM64::CheckNotCharacterAfterMinusAnd(
536 Label* on_not_equal) {
537 DCHECK_GT(String::kMaxUtf16CodeUnit, minus);
538 __ Sub(w10, current_character(), minus);
539 __ And(w10, w10, mask);
540 CompareAndBranchOrBacktrack(w10, c, ne, on_not_equal);
544 void RegExpMacroAssemblerARM64::CheckCharacterInRange(
547 Label* on_in_range) {
548 __ Sub(w10, current_character(), from);
550 CompareAndBranchOrBacktrack(w10, to - from, ls, on_in_range);
554 void RegExpMacroAssemblerARM64::CheckCharacterNotInRange(
557 Label* on_not_in_range) {
558 __ Sub(w10, current_character(), from);
560 CompareAndBranchOrBacktrack(w10, to - from, hi, on_not_in_range);
564 void RegExpMacroAssemblerARM64::CheckBitInTable(
565 Handle<ByteArray> table,
567 __ Mov(x11, Operand(table));
568 if ((mode_ != LATIN1) || (kTableMask != String::kMaxOneByteCharCode)) {
569 __ And(w10, current_character(), kTableMask);
570 __ Add(w10, w10, ByteArray::kHeaderSize - kHeapObjectTag);
572 __ Add(w10, current_character(), ByteArray::kHeaderSize - kHeapObjectTag);
574 __ Ldrb(w11, MemOperand(x11, w10, UXTW));
575 CompareAndBranchOrBacktrack(w11, 0, ne, on_bit_set);
579 bool RegExpMacroAssemblerARM64::CheckSpecialCharacterClass(uc16 type,
580 Label* on_no_match) {
586 if (mode_ == LATIN1) {
590 __ Cmp(current_character(),
' ');
591 __ Ccmp(current_character(), 0x00A0, ZFlag, ne);
594 __ Sub(w10, current_character(),
'\t');
595 CompareAndBranchOrBacktrack(w10,
'\r' -
'\t', hi, on_no_match);
605 __ Sub(w10, current_character(),
'0');
606 CompareAndBranchOrBacktrack(w10,
'9' -
'0', hi, on_no_match);
610 __ Sub(w10, current_character(),
'0');
611 CompareAndBranchOrBacktrack(w10,
'9' -
'0', ls, on_no_match);
618 __ Cmp(current_character(), 0x0A);
619 __ Ccmp(current_character(), 0x0D, ZFlag, ne);
621 __ Sub(w10, current_character(), 0x2028);
623 __ Ccmp(w10, 0x2029 - 0x2028, NoFlag, ne);
625 BranchOrBacktrack(ls, on_no_match);
627 BranchOrBacktrack(eq, on_no_match);
635 __ Cmp(current_character(), 0x0A);
636 __ Ccmp(current_character(), 0x0D, ZFlag, ne);
638 __ Sub(w10, current_character(), 0x2028);
640 __ Ccmp(w10, 0x2029 - 0x2028, NoFlag, ne);
642 BranchOrBacktrack(hi, on_no_match);
644 BranchOrBacktrack(ne, on_no_match);
649 if (mode_ != LATIN1) {
651 CompareAndBranchOrBacktrack(current_character(),
'z', hi, on_no_match);
653 ExternalReference map = ExternalReference::re_word_character_map(isolate());
655 __ Ldrb(w10, MemOperand(x10, current_character(), UXTW));
656 CompareAndBranchOrBacktrack(w10, 0, eq, on_no_match);
661 if (mode_ != LATIN1) {
663 __ Cmp(current_character(),
'z');
666 ExternalReference map = ExternalReference::re_word_character_map(isolate());
668 __ Ldrb(w10, MemOperand(x10, current_character(), UXTW));
669 CompareAndBranchOrBacktrack(w10, 0, ne, on_no_match);
683 void RegExpMacroAssemblerARM64::Fail() {
689 Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
695 __ Bind(&entry_label_);
712 FrameScope scope(masm_, StackFrame::MANUAL);
715 CPURegList argument_registers(x0, x5, x6, x7);
717 CPURegList registers_to_retain = kCalleeSaved;
718 DCHECK_EQ(11, kCalleeSaved.Count());
719 registers_to_retain.Combine(lr);
721 __ PushCPURegList(registers_to_retain);
722 __ PushCPURegList(argument_registers);
725 __ Add(frame_pointer(), sp, argument_registers.Count() * kPointerSize);
728 __ Mov(start_offset(), w1);
729 __ Mov(input_start(), x2);
730 __ Mov(input_end(), x3);
731 __ Mov(output_array(), x4);
736 int num_wreg_to_allocate = num_registers_ - kNumCachedRegisters;
738 if (num_wreg_to_allocate < 0) { num_wreg_to_allocate = 0; }
740 num_wreg_to_allocate += 2;
743 int alignment = masm_->ActivationFrameAlignment();
744 DCHECK_EQ(alignment % 16, 0);
745 int align_mask = (alignment / kWRegSize) - 1;
746 num_wreg_to_allocate = (num_wreg_to_allocate + align_mask) & ~align_mask;
749 Label stack_limit_hit;
752 ExternalReference stack_limit =
753 ExternalReference::address_of_stack_limit(isolate());
754 __ Mov(x10, stack_limit);
755 __ Ldr(x10, MemOperand(x10));
756 __ Subs(x10, sp, x10);
759 __ B(ls, &stack_limit_hit);
763 __ Cmp(x10, num_wreg_to_allocate * kWRegSize);
768 __ Mov(w0, EXCEPTION);
771 __ Bind(&stack_limit_hit);
772 CallCheckStackGuardState(x10);
774 __ Cbnz(w0, &return_w0);
779 __ Claim(num_wreg_to_allocate, kWRegSize);
782 __ Str(wzr, MemOperand(frame_pointer(), kSuccessCounter));
785 __ Sub(x10, input_start(), input_end());
786 if (masm_->emit_debug_code()) {
789 __ Cmp(x11, SeqTwoByteString::kMaxCharsSize);
790 __ Check(ls, AbortReason::kInputStringTooLong);
792 __ Mov(current_input_offset(), w10);
797 __ Sub(string_start_minus_one(), current_input_offset(), char_size());
798 __ Sub(string_start_minus_one(), string_start_minus_one(),
799 Operand(start_offset(), LSL, (mode_ == UC16) ? 1 : 0));
802 __ Orr(twice_non_position_value(), string_start_minus_one().X(),
803 Operand(string_start_minus_one().X(), LSL, kWRegSizeInBits));
806 __ Mov(code_pointer(), Operand(masm_->CodeObject()));
808 Label load_char_start_regexp, start_regexp;
810 __ Cbnz(start_offset(), &load_char_start_regexp);
811 __ Mov(current_character(),
'\n');
815 __ Bind(&load_char_start_regexp);
817 LoadCurrentCharacterUnchecked(-1, 1);
818 __ Bind(&start_regexp);
820 if (num_saved_registers_ > 0) {
821 ClearRegisters(0, num_saved_registers_ - 1);
825 __ Ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackBase));
830 if (backtrack_label_.is_linked()) {
831 __ Bind(&backtrack_label_);
835 if (success_label_.is_linked()) {
836 Register first_capture_start = w15;
839 __ Bind(&success_label_);
841 if (num_saved_registers_ > 0) {
843 Register capture_start = w12;
844 Register capture_end = w13;
845 Register input_length = w14;
850 __ Sub(x10, input_end(), input_start());
851 if (masm_->emit_debug_code()) {
853 __ Cmp(x10, SeqTwoByteString::kMaxCharsSize);
854 __ Check(ls, AbortReason::kInputStringTooLong);
859 __ Add(input_length, start_offset(), Operand(w10, LSR, 1));
861 __ Add(input_length, start_offset(), w10);
866 (
i < num_saved_registers_) && (
i < kNumCachedRegisters);
868 __ Mov(capture_start.X(), GetCachedRegister(
i));
869 __ Lsr(capture_end.X(), capture_start.X(), kWRegSizeInBits);
870 if ((
i == 0) && global_with_zero_length_check()) {
872 __ Mov(first_capture_start, capture_start);
876 __ Add(capture_start, input_length, Operand(capture_start, ASR, 1));
877 __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
879 __ Add(capture_start, input_length, capture_start);
880 __ Add(capture_end, input_length, capture_end);
883 __ Stp(capture_start,
885 MemOperand(output_array(), kPointerSize, PostIndex));
890 int num_registers_left_on_stack =
891 num_saved_registers_ - kNumCachedRegisters;
892 if (num_registers_left_on_stack > 0) {
896 DCHECK_EQ(0, num_registers_left_on_stack % 2);
897 __ Add(base, frame_pointer(), kFirstCaptureOnStack);
901 STATIC_ASSERT(kNumRegistersToUnroll > 2);
902 if (num_registers_left_on_stack <= kNumRegistersToUnroll) {
903 for (
int i = 0;
i < num_registers_left_on_stack / 2;
i++) {
906 MemOperand(base, -kPointerSize, PostIndex));
907 if ((
i == 0) && global_with_zero_length_check()) {
909 __ Mov(first_capture_start, capture_start);
913 __ Add(capture_start,
915 Operand(capture_start, ASR, 1));
916 __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
918 __ Add(capture_start, input_length, capture_start);
919 __ Add(capture_end, input_length, capture_end);
922 __ Stp(capture_start,
924 MemOperand(output_array(), kPointerSize, PostIndex));
928 __ Mov(x11, num_registers_left_on_stack);
932 MemOperand(base, -kPointerSize, PostIndex));
933 if (global_with_zero_length_check()) {
934 __ Mov(first_capture_start, capture_start);
941 MemOperand(base, -kPointerSize, PostIndex));
944 __ Add(capture_start, input_length, Operand(capture_start, ASR, 1));
945 __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
947 __ Add(capture_start, input_length, capture_start);
948 __ Add(capture_end, input_length, capture_end);
951 __ Stp(capture_start,
953 MemOperand(output_array(), kPointerSize, PostIndex));
961 Register success_counter = w0;
962 Register output_size = x10;
966 __ Ldr(success_counter, MemOperand(frame_pointer(), kSuccessCounter));
967 __ Add(success_counter, success_counter, 1);
968 __ Str(success_counter, MemOperand(frame_pointer(), kSuccessCounter));
972 __ Ldr(output_size, MemOperand(frame_pointer(), kOutputSize));
973 __ Sub(output_size, output_size, num_saved_registers_);
975 __ Cmp(output_size, num_saved_registers_);
976 __ B(lt, &return_w0);
981 __ Str(output_size, MemOperand(frame_pointer(), kOutputSize));
983 if (global_with_zero_length_check()) {
985 __ Cmp(current_input_offset(), first_capture_start);
987 __ B(ne, &load_char_start_regexp);
989 __ Cbz(current_input_offset(), &return_w0);
993 __ Add(current_input_offset(),
994 current_input_offset(),
995 Operand((mode_ == UC16) ? 2 : 1));
996 if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
999 __ B(&load_char_start_regexp);
1001 __ Mov(w0, SUCCESS);
1005 if (exit_label_.is_linked()) {
1007 __ Bind(&exit_label_);
1009 __ Ldr(w0, MemOperand(frame_pointer(), kSuccessCounter));
1013 __ Bind(&return_w0);
1019 __ PopCPURegList(registers_to_retain);
1023 Label exit_with_exception;
1026 CPURegList cached_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 7);
1027 DCHECK_EQ(kNumCachedRegisters, cached_registers.Count() * 2);
1029 if (check_preempt_label_.is_linked()) {
1030 __ Bind(&check_preempt_label_);
1033 __ PushCPURegList(cached_registers);
1034 CallCheckStackGuardState(x10);
1037 __ Cbnz(w0, &return_w0);
1039 __ PopCPURegList(cached_registers);
1040 RestoreLinkRegister();
1044 if (stack_overflow_label_.is_linked()) {
1045 __ Bind(&stack_overflow_label_);
1048 __ PushCPURegList(cached_registers);
1050 __ Mov(x2, ExternalReference::isolate_address(isolate()));
1051 __ Add(x1, frame_pointer(), kStackBase);
1052 __ Mov(x0, backtrack_stackpointer());
1053 ExternalReference grow_stack =
1054 ExternalReference::re_grow_stack(isolate());
1055 __ CallCFunction(grow_stack, 3);
1060 __ Cbz(w0, &exit_with_exception);
1062 __ Mov(backtrack_stackpointer(), x0);
1064 __ PopCPURegList(cached_registers);
1065 RestoreLinkRegister();
1069 if (exit_with_exception.is_linked()) {
1070 __ Bind(&exit_with_exception);
1071 __ Mov(w0, EXCEPTION);
1076 masm_->GetCode(isolate(), &code_desc);
1077 Handle<Code> code = isolate()->factory()->NewCode(code_desc, Code::REGEXP,
1078 masm_->CodeObject());
1079 PROFILE(masm_->isolate(),
1080 RegExpCodeCreateEvent(AbstractCode::cast(*code), *source));
1081 return Handle<HeapObject>::cast(code);
1085 void RegExpMacroAssemblerARM64::GoTo(Label* to) {
1086 BranchOrBacktrack(al, to);
1089 void RegExpMacroAssemblerARM64::IfRegisterGE(
int reg,
int comparand,
1091 Register to_compare = GetRegister(reg, w10);
1092 CompareAndBranchOrBacktrack(to_compare, comparand, ge, if_ge);
1096 void RegExpMacroAssemblerARM64::IfRegisterLT(
int reg,
int comparand,
1098 Register to_compare = GetRegister(reg, w10);
1099 CompareAndBranchOrBacktrack(to_compare, comparand, lt, if_lt);
1103 void RegExpMacroAssemblerARM64::IfRegisterEqPos(
int reg, Label* if_eq) {
1104 Register to_compare = GetRegister(reg, w10);
1105 __ Cmp(to_compare, current_input_offset());
1106 BranchOrBacktrack(eq, if_eq);
1109 RegExpMacroAssembler::IrregexpImplementation
1110 RegExpMacroAssemblerARM64::Implementation() {
1111 return kARM64Implementation;
1115 void RegExpMacroAssemblerARM64::LoadCurrentCharacter(
int cp_offset,
1116 Label* on_end_of_input,
1122 DCHECK(cp_offset < (1<<30));
1124 if (cp_offset >= 0) {
1125 CheckPosition(cp_offset + characters - 1, on_end_of_input);
1127 CheckPosition(cp_offset, on_end_of_input);
1130 LoadCurrentCharacterUnchecked(cp_offset, characters);
1134 void RegExpMacroAssemblerARM64::PopCurrentPosition() {
1135 Pop(current_input_offset());
1139 void RegExpMacroAssemblerARM64::PopRegister(
int register_index) {
1141 StoreRegister(register_index, w10);
1145 void RegExpMacroAssemblerARM64::PushBacktrack(Label* label) {
1146 if (label->is_bound()) {
1147 int target = label->pos();
1148 __ Mov(w10, target + Code::kHeaderSize - kHeapObjectTag);
1150 __ Adr(x10, label, MacroAssembler::kAdrFar);
1151 __ Sub(x10, x10, code_pointer());
1152 if (masm_->emit_debug_code()) {
1153 __ Cmp(x10, kWRegMask);
1155 __ Check(ls, AbortReason::kOffsetOutOfRange);
1163 void RegExpMacroAssemblerARM64::PushCurrentPosition() {
1164 Push(current_input_offset());
1168 void RegExpMacroAssemblerARM64::PushRegister(
int register_index,
1169 StackCheckFlag check_stack_limit) {
1170 Register to_push = GetRegister(register_index, w10);
1172 if (check_stack_limit) CheckStackLimit();
1176 void RegExpMacroAssemblerARM64::ReadCurrentPositionFromRegister(
int reg) {
1177 RegisterState register_state = GetRegisterState(reg);
1178 switch (register_state) {
1180 __ Ldr(current_input_offset(), register_location(reg));
1183 __ Mov(current_input_offset(), GetCachedRegister(reg).W());
1186 __ Lsr(current_input_offset().X(), GetCachedRegister(reg),
1196 void RegExpMacroAssemblerARM64::ReadStackPointerFromRegister(
int reg) {
1197 Register read_from = GetRegister(reg, w10);
1198 __ Ldr(x11, MemOperand(frame_pointer(), kStackBase));
1199 __ Add(backtrack_stackpointer(), x11, Operand(read_from, SXTW));
1203 void RegExpMacroAssemblerARM64::SetCurrentPositionFromEnd(
int by) {
1204 Label after_position;
1205 __ Cmp(current_input_offset(), -by * char_size());
1206 __ B(ge, &after_position);
1207 __ Mov(current_input_offset(), -by * char_size());
1211 LoadCurrentCharacterUnchecked(-1, 1);
1212 __ Bind(&after_position);
1216 void RegExpMacroAssemblerARM64::SetRegister(
int register_index,
int to) {
1217 DCHECK(register_index >= num_saved_registers_);
1218 Register set_to = wzr;
1223 StoreRegister(register_index, set_to);
1227 bool RegExpMacroAssemblerARM64::Succeed() {
1228 __ B(&success_label_);
1233 void RegExpMacroAssemblerARM64::WriteCurrentPositionToRegister(
int reg,
1235 Register position = current_input_offset();
1236 if (cp_offset != 0) {
1238 __ Add(position, current_input_offset(), cp_offset * char_size());
1240 StoreRegister(reg, position);
1244 void RegExpMacroAssemblerARM64::ClearRegisters(
int reg_from,
int reg_to) {
1245 DCHECK(reg_from <= reg_to);
1246 int num_registers = reg_to - reg_from + 1;
1250 if ((reg_from < kNumCachedRegisters) && ((reg_from % 2) != 0)) {
1251 StoreRegister(reg_from, string_start_minus_one());
1257 while ((num_registers >= 2) && (reg_from < kNumCachedRegisters)) {
1258 DCHECK(GetRegisterState(reg_from) == CACHED_LSW);
1259 __ Mov(GetCachedRegister(reg_from), twice_non_position_value());
1264 if ((num_registers % 2) == 1) {
1265 StoreRegister(reg_from, string_start_minus_one());
1270 if (num_registers > 0) {
1272 DCHECK_LE(kNumCachedRegisters, reg_from);
1276 reg_from -= kNumCachedRegisters;
1277 reg_to -= kNumCachedRegisters;
1279 STATIC_ASSERT(kNumRegistersToUnroll > 2);
1281 int base_offset = kFirstRegisterOnStack -
1282 kWRegSize - (kWRegSize * reg_from);
1283 if (num_registers > kNumRegistersToUnroll) {
1284 Register base = x10;
1285 __ Add(base, frame_pointer(), base_offset);
1288 __ Mov(x11, num_registers);
1290 __ Str(twice_non_position_value(),
1291 MemOperand(base, -kPointerSize, PostIndex));
1292 __ Sub(x11, x11, 2);
1293 __ Cbnz(x11, &loop);
1295 for (
int i = reg_from;
i <= reg_to;
i += 2) {
1296 __ Str(twice_non_position_value(),
1297 MemOperand(frame_pointer(), base_offset));
1298 base_offset -= kWRegSize * 2;
1305 void RegExpMacroAssemblerARM64::WriteStackPointerToRegister(
int reg) {
1306 __ Ldr(x10, MemOperand(frame_pointer(), kStackBase));
1307 __ Sub(x10, backtrack_stackpointer(), x10);
1308 if (masm_->emit_debug_code()) {
1309 __ Cmp(x10, Operand(w10, SXTW));
1311 __ Check(eq, AbortReason::kOffsetOutOfRange);
1313 StoreRegister(reg, w10);
1318 template <
typename T>
1319 static T& frame_entry(Address re_frame,
int frame_offset) {
1320 return *
reinterpret_cast<T*
>(re_frame + frame_offset);
1324 template <
typename T>
1325 static T* frame_entry_address(Address re_frame,
int frame_offset) {
1326 return reinterpret_cast<T*
>(re_frame + frame_offset);
1329 int RegExpMacroAssemblerARM64::CheckStackGuardState(
1330 Address* return_address, Address raw_code, Address re_frame,
1331 int start_index,
const byte** input_start,
const byte** input_end) {
1332 Code re_code = Code::cast(ObjectPtr(raw_code));
1333 return NativeRegExpMacroAssembler::CheckStackGuardState(
1334 frame_entry<Isolate*>(re_frame, kIsolate), start_index,
1335 frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
1336 frame_entry_address<Address>(re_frame, kInput), input_start, input_end);
1340 void RegExpMacroAssemblerARM64::CheckPosition(
int cp_offset,
1341 Label* on_outside_input) {
1342 if (cp_offset >= 0) {
1343 CompareAndBranchOrBacktrack(current_input_offset(),
1344 -cp_offset * char_size(), ge, on_outside_input);
1346 __ Add(w12, current_input_offset(), Operand(cp_offset * char_size()));
1347 __ Cmp(w12, string_start_minus_one());
1348 BranchOrBacktrack(le, on_outside_input);
1355 void RegExpMacroAssemblerARM64::CallCheckStackGuardState(Register scratch) {
1360 int alignment = masm_->ActivationFrameAlignment();
1361 DCHECK_EQ(alignment % 16, 0);
1362 int align_mask = (alignment / kXRegSize) - 1;
1363 int xreg_to_claim = (3 + align_mask) & ~align_mask;
1365 __ Claim(xreg_to_claim);
1368 __ Poke(input_end(), 2 * kPointerSize);
1369 __ Add(x5, sp, 2 * kPointerSize);
1370 __ Poke(input_start(), kPointerSize);
1371 __ Add(x4, sp, kPointerSize);
1373 __ Mov(w3, start_offset());
1375 __ Mov(x2, frame_pointer());
1377 __ Mov(x1, Operand(masm_->CodeObject()));
1384 ExternalReference check_stack_guard_state =
1385 ExternalReference::re_check_stack_guard_state(isolate());
1386 __ Mov(scratch, check_stack_guard_state);
1387 DirectCEntryStub stub(isolate());
1388 stub.GenerateCall(masm_, scratch);
1391 __ Peek(input_start(), kPointerSize);
1392 __ Peek(input_end(), 2 * kPointerSize);
1394 __ Drop(xreg_to_claim);
1397 __ Mov(code_pointer(), Operand(masm_->CodeObject()));
1400 void RegExpMacroAssemblerARM64::BranchOrBacktrack(Condition condition,
1402 if (condition == al) {
1403 if (to ==
nullptr) {
1410 if (to ==
nullptr) {
1411 to = &backtrack_label_;
1413 __ B(condition, to);
1416 void RegExpMacroAssemblerARM64::CompareAndBranchOrBacktrack(Register reg,
1418 Condition condition,
1420 if ((immediate == 0) && ((condition == eq) || (condition == ne))) {
1421 if (to ==
nullptr) {
1422 to = &backtrack_label_;
1424 if (condition == eq) {
1430 __ Cmp(reg, immediate);
1431 BranchOrBacktrack(condition, to);
1436 void RegExpMacroAssemblerARM64::CheckPreemption() {
1438 ExternalReference stack_limit =
1439 ExternalReference::address_of_stack_limit(isolate());
1440 __ Mov(x10, stack_limit);
1441 __ Ldr(x10, MemOperand(x10));
1443 CallIf(&check_preempt_label_, ls);
1447 void RegExpMacroAssemblerARM64::CheckStackLimit() {
1448 ExternalReference stack_limit =
1449 ExternalReference::address_of_regexp_stack_limit(isolate());
1450 __ Mov(x10, stack_limit);
1451 __ Ldr(x10, MemOperand(x10));
1452 __ Cmp(backtrack_stackpointer(), x10);
1453 CallIf(&stack_overflow_label_, ls);
1457 void RegExpMacroAssemblerARM64::Push(Register source) {
1458 DCHECK(source.Is32Bits());
1459 DCHECK(!source.is(backtrack_stackpointer()));
1461 MemOperand(backtrack_stackpointer(),
1462 -static_cast<int>(kWRegSize),
1467 void RegExpMacroAssemblerARM64::Pop(Register target) {
1468 DCHECK(target.Is32Bits());
1469 DCHECK(!target.is(backtrack_stackpointer()));
1471 MemOperand(backtrack_stackpointer(), kWRegSize, PostIndex));
1475 Register RegExpMacroAssemblerARM64::GetCachedRegister(
int register_index) {
1476 DCHECK_GT(kNumCachedRegisters, register_index);
1477 return Register::Create(register_index / 2, kXRegSizeInBits);
1481 Register RegExpMacroAssemblerARM64::GetRegister(
int register_index,
1482 Register maybe_result) {
1483 DCHECK(maybe_result.Is32Bits());
1484 DCHECK_LE(0, register_index);
1485 if (num_registers_ <= register_index) {
1486 num_registers_ = register_index + 1;
1488 Register result = NoReg;
1489 RegisterState register_state = GetRegisterState(register_index);
1490 switch (register_state) {
1492 __ Ldr(maybe_result, register_location(register_index));
1493 result = maybe_result;
1496 result = GetCachedRegister(register_index).W();
1499 __ Lsr(maybe_result.X(), GetCachedRegister(register_index),
1501 result = maybe_result;
1507 DCHECK(result.Is32Bits());
1512 void RegExpMacroAssemblerARM64::StoreRegister(
int register_index,
1514 DCHECK(source.Is32Bits());
1515 DCHECK_LE(0, register_index);
1516 if (num_registers_ <= register_index) {
1517 num_registers_ = register_index + 1;
1520 RegisterState register_state = GetRegisterState(register_index);
1521 switch (register_state) {
1523 __ Str(source, register_location(register_index));
1526 Register cached_register = GetCachedRegister(register_index);
1527 if (!source.Is(cached_register.W())) {
1528 __ Bfi(cached_register, source.X(), 0, kWRegSizeInBits);
1533 Register cached_register = GetCachedRegister(register_index);
1534 __ Bfi(cached_register, source.X(), kWRegSizeInBits, kWRegSizeInBits);
1544 void RegExpMacroAssemblerARM64::CallIf(Label* to, Condition condition) {
1546 if (condition != al) __ B(&skip_call, NegateCondition(condition));
1548 __ Bind(&skip_call);
1552 void RegExpMacroAssemblerARM64::RestoreLinkRegister() {
1554 __ Add(lr, lr, Operand(masm_->CodeObject()));
1558 void RegExpMacroAssemblerARM64::SaveLinkRegister() {
1559 __ Sub(lr, lr, Operand(masm_->CodeObject()));
1564 MemOperand RegExpMacroAssemblerARM64::register_location(
int register_index) {
1565 DCHECK(register_index < (1<<30));
1566 DCHECK_LE(kNumCachedRegisters, register_index);
1567 if (num_registers_ <= register_index) {
1568 num_registers_ = register_index + 1;
1570 register_index -= kNumCachedRegisters;
1571 int offset = kFirstRegisterOnStack - register_index * kWRegSize;
1572 return MemOperand(frame_pointer(), offset);
1575 MemOperand RegExpMacroAssemblerARM64::capture_location(
int register_index,
1577 DCHECK(register_index < (1<<30));
1578 DCHECK(register_index < num_saved_registers_);
1579 DCHECK_LE(kNumCachedRegisters, register_index);
1580 DCHECK_EQ(register_index % 2, 0);
1581 register_index -= kNumCachedRegisters;
1582 int offset = kFirstCaptureOnStack - register_index * kWRegSize;
1585 if (is_int7(offset)) {
1586 return MemOperand(frame_pointer(), offset);
1588 __ Add(scratch, frame_pointer(), offset);
1589 return MemOperand(scratch);
1593 void RegExpMacroAssemblerARM64::LoadCurrentCharacterUnchecked(
int cp_offset,
1595 Register offset = current_input_offset();
1605 if (!CanReadUnaligned()) {
1606 DCHECK_EQ(1, characters);
1609 if (cp_offset != 0) {
1610 if (masm_->emit_debug_code()) {
1611 __ Mov(x10, cp_offset * char_size());
1612 __ Add(x10, x10, Operand(current_input_offset(), SXTW));
1613 __ Cmp(x10, Operand(w10, SXTW));
1615 __ Check(eq, AbortReason::kOffsetOutOfRange);
1617 __ Add(w10, current_input_offset(), cp_offset * char_size());
1622 if (mode_ == LATIN1) {
1623 if (characters == 4) {
1624 __ Ldr(current_character(), MemOperand(input_end(), offset, SXTW));
1625 }
else if (characters == 2) {
1626 __ Ldrh(current_character(), MemOperand(input_end(), offset, SXTW));
1628 DCHECK_EQ(1, characters);
1629 __ Ldrb(current_character(), MemOperand(input_end(), offset, SXTW));
1632 DCHECK(mode_ == UC16);
1633 if (characters == 2) {
1634 __ Ldr(current_character(), MemOperand(input_end(), offset, SXTW));
1636 DCHECK_EQ(1, characters);
1637 __ Ldrh(current_character(), MemOperand(input_end(), offset, SXTW));
1642 #endif // V8_INTERPRETED_REGEXP 1649 #endif // V8_TARGET_ARCH_ARM64