95#define __ ACCESS_MASM((&masm_))
101 int registers_to_save)
102 : NativeRegExpMacroAssembler(isolate, zone),
105 no_root_array_scope_(&
masm_),
106 code_relative_fixup_positions_(zone),
108 num_registers_(registers_to_save),
109 num_saved_registers_(registers_to_save),
117 __ jmp(&entry_label_);
118 __ bind(&start_label_);
121RegExpMacroAssemblerX64::~RegExpMacroAssemblerX64() {
123 entry_label_.Unuse();
124 start_label_.Unuse();
125 success_label_.Unuse();
126 backtrack_label_.Unuse();
128 check_preempt_label_.Unuse();
129 stack_overflow_label_.Unuse();
130 fallback_label_.Unuse();
133int RegExpMacroAssemblerX64::stack_limit_slack_slot_count() {
134 return RegExpStack::kStackLimitSlackSlotCount;
137void RegExpMacroAssemblerX64::AdvanceCurrentPosition(
int by) {
139 __ addq(rdi, Immediate(by * char_size()));
144void RegExpMacroAssemblerX64::AdvanceRegister(
int reg,
int by) {
148 __ addq(register_location(
reg), Immediate(by));
153void RegExpMacroAssemblerX64::Backtrack() {
155 if (has_backtrack_limit()) {
157 __ incq(Operand(rbp, kBacktrackCountOffset));
158 __ cmpq(Operand(rbp, kBacktrackCountOffset), Immediate(backtrack_limit()));
159 __ j(not_equal, &next);
162 if (can_fallback()) {
163 __ jmp(&fallback_label_);
174 __ addq(rbx, code_object_pointer());
182void RegExpMacroAssemblerX64::Bind(Label*
label) {
187void RegExpMacroAssemblerX64::CheckCharacter(uint32_t c, Label* on_equal) {
188 __ cmpl(current_character(), Immediate(c));
189 BranchOrBacktrack(equal, on_equal);
192void RegExpMacroAssemblerX64::CheckCharacterGT(base::uc16 limit,
194 __ cmpl(current_character(), Immediate(limit));
195 BranchOrBacktrack(greater, on_greater);
198void RegExpMacroAssemblerX64::CheckAtStart(
int cp_offset, Label* on_at_start) {
199 __ leaq(rax, Operand(rdi, -char_size() + cp_offset * char_size()));
200 __ cmpq(rax, Operand(rbp, kStringStartMinusOneOffset));
201 BranchOrBacktrack(equal, on_at_start);
204void RegExpMacroAssemblerX64::CheckNotAtStart(
int cp_offset,
205 Label* on_not_at_start) {
206 __ leaq(rax, Operand(rdi, -char_size() + cp_offset * char_size()));
207 __ cmpq(rax, Operand(rbp, kStringStartMinusOneOffset));
208 BranchOrBacktrack(not_equal, on_not_at_start);
211void RegExpMacroAssemblerX64::CheckCharacterLT(base::uc16 limit,
213 __ cmpl(current_character(), Immediate(limit));
214 BranchOrBacktrack(less, on_less);
217void RegExpMacroAssemblerX64::CheckGreedyLoop(Label* on_equal) {
219 __ cmpl(rdi, Operand(backtrack_stackpointer(), 0));
220 __ j(not_equal, &fallthrough);
222 BranchOrBacktrack(on_equal);
223 __ bind(&fallthrough);
226void RegExpMacroAssemblerX64::CallCFunctionFromIrregexpCode(
227 ExternalReference function,
int num_arguments) {
242void RegExpMacroAssemblerX64::PushCallerSavedRegisters() {
243#ifndef V8_TARGET_OS_WIN
251void RegExpMacroAssemblerX64::PopCallerSavedRegisters() {
253#ifndef V8_TARGET_OS_WIN
259void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
260 int start_reg,
bool read_backward,
bool unicode, Label* on_no_match) {
262 ReadPositionFromRegister(rdx, start_reg);
263 ReadPositionFromRegister(rbx, start_reg + 1);
273 __ j(equal, &fallthrough);
280 __ movl(rax, Operand(rbp, kStringStartMinusOneOffset));
283 BranchOrBacktrack(less_equal, on_no_match);
287 BranchOrBacktrack(greater, on_no_match);
290 if (
mode_ == LATIN1) {
291 Label loop_increment;
292 if (on_no_match ==
nullptr) {
293 on_no_match = &backtrack_label_;
296 __ leaq(r9, Operand(rsi, rdx, times_1, 0));
297 __ leaq(r11, Operand(rsi, rdi, times_1, 0));
309 __ movzxbl(rdx, Operand(r9, 0));
310 __ movzxbl(rax, Operand(r11, 0));
314 __ j(equal, &loop_increment);
319 __ orq(rax, Immediate(0x20));
320 __ orq(rdx, Immediate(0x20));
322 __ j(not_equal, on_no_match);
323 __ subb(rax, Immediate(
'a'));
324 __ cmpb(rax, Immediate(
'z' -
'a'));
325 __ j(below_equal, &loop_increment);
327 __ subb(rax, Immediate(224 -
'a'));
328 __ cmpb(rax, Immediate(254 - 224));
329 __ j(above, on_no_match);
330 __ cmpb(rax, Immediate(247 - 224));
331 __ j(equal, on_no_match);
332 __ bind(&loop_increment);
334 __ addq(r11, Immediate(1));
335 __ addq(r9, Immediate(1));
345 __ addq(rdi, register_location(start_reg));
346 __ subq(rdi, register_location(start_reg + 1));
350 PushCallerSavedRegisters();
352 static const int num_arguments = 4;
353 __ PrepareCallCFunction(num_arguments);
360#ifdef V8_TARGET_OS_WIN
361 DCHECK(rcx == kCArgRegs[0]);
362 DCHECK(rdx == kCArgRegs[1]);
364 __ leaq(rcx, Operand(rsi, rdx, times_1, 0));
366 __ leaq(rdx, Operand(rsi, rdi, times_1, 0));
371 DCHECK(rdi == kCArgRegs[0]);
372 DCHECK(rsi == kCArgRegs[1]);
374 __ leaq(rax, Operand(rsi, rdi, times_1, 0));
376 __ leaq(rdi, Operand(rsi, rdx, times_1, 0));
385 __ movq(kCArgRegs[2], rbx);
387 __ LoadAddress(kCArgRegs[3], ExternalReference::isolate_address(
isolate()));
390 AllowExternalCallThatCantCauseGC scope(&
masm_);
393 ? ExternalReference::re_case_insensitive_compare_unicode()
394 : ExternalReference::re_case_insensitive_compare_non_unicode();
395 CallCFunctionFromIrregexpCode(
compare, num_arguments);
399 __ Move(code_object_pointer(),
masm_.CodeObject());
400 PopCallerSavedRegisters();
404 BranchOrBacktrack(zero, on_no_match);
413 __ bind(&fallthrough);
416void RegExpMacroAssemblerX64::CheckNotBackReference(
int start_reg,
418 Label* on_no_match) {
422 ReadPositionFromRegister(rdx, start_reg);
423 ReadPositionFromRegister(rax, start_reg + 1);
429 __ j(equal, &fallthrough);
436 __ movl(rbx, Operand(rbp, kStringStartMinusOneOffset));
439 BranchOrBacktrack(less_equal, on_no_match);
443 BranchOrBacktrack(greater, on_no_match);
447 __ leaq(rbx, Operand(rsi, rdi, times_1, 0));
452 __ leaq(r9, Operand(rdx, rax, times_1, 0));
461 if (
mode_ == LATIN1) {
462 __ movzxbl(rax, Operand(rdx, 0));
463 __ cmpb(rax, Operand(rbx, 0));
466 __ movzxwl(rax, Operand(rdx, 0));
467 __ cmpw(rax, Operand(rbx, 0));
469 BranchOrBacktrack(not_equal, on_no_match);
471 __ addq(rbx, Immediate(char_size()));
472 __ addq(rdx, Immediate(char_size()));
483 __ addq(rdi, register_location(start_reg));
484 __ subq(rdi, register_location(start_reg + 1));
487 __ bind(&fallthrough);
491void RegExpMacroAssemblerX64::CheckNotCharacter(uint32_t c,
492 Label* on_not_equal) {
493 __ cmpl(current_character(), Immediate(c));
494 BranchOrBacktrack(not_equal, on_not_equal);
498void RegExpMacroAssemblerX64::CheckCharacterAfterAnd(uint32_t c,
502 __ testl(current_character(), Immediate(
mask));
505 __ andq(rax, current_character());
506 __ cmpl(rax, Immediate(c));
508 BranchOrBacktrack(equal, on_equal);
512void RegExpMacroAssemblerX64::CheckNotCharacterAfterAnd(uint32_t c,
514 Label* on_not_equal) {
516 __ testl(current_character(), Immediate(
mask));
519 __ andq(rax, current_character());
520 __ cmpl(rax, Immediate(c));
522 BranchOrBacktrack(not_equal, on_not_equal);
525void RegExpMacroAssemblerX64::CheckNotCharacterAfterMinusAnd(
526 base::uc16 c, base::uc16 minus, base::uc16
mask, Label* on_not_equal) {
527 DCHECK_GT(String::kMaxUtf16CodeUnit, minus);
528 __ leal(rax, Operand(current_character(), -minus));
529 __ andl(rax, Immediate(
mask));
530 __ cmpl(rax, Immediate(c));
531 BranchOrBacktrack(not_equal, on_not_equal);
534void RegExpMacroAssemblerX64::CheckCharacterInRange(base::uc16 from,
536 Label* on_in_range) {
537 __ leal(rax, Operand(current_character(), -from));
538 __ cmpl(rax, Immediate(to - from));
539 BranchOrBacktrack(below_equal, on_in_range);
542void RegExpMacroAssemblerX64::CheckCharacterNotInRange(base::uc16 from,
544 Label* on_not_in_range) {
545 __ leal(rax, Operand(current_character(), -from));
546 __ cmpl(rax, Immediate(to - from));
547 BranchOrBacktrack(above, on_not_in_range);
550void RegExpMacroAssemblerX64::CallIsCharacterInRangeArray(
551 const ZoneList<CharacterRange>* ranges) {
552 PushCallerSavedRegisters();
554 static const int kNumArguments = 2;
555 __ PrepareCallCFunction(kNumArguments);
557 __ Move(kCArgRegs[0], current_character());
558 __ Move(kCArgRegs[1], GetOrAddRangeArray(ranges));
562 FrameScope scope(&
masm_, StackFrame::MANUAL);
563 CallCFunctionFromIrregexpCode(
564 ExternalReference::re_is_character_in_range_array(), kNumArguments);
567 PopCallerSavedRegisters();
568 __ Move(code_object_pointer(),
masm_.CodeObject());
571bool RegExpMacroAssemblerX64::CheckCharacterInRangeArray(
572 const ZoneList<CharacterRange>* ranges, Label* on_in_range) {
573 CallIsCharacterInRangeArray(ranges);
575 BranchOrBacktrack(not_zero, on_in_range);
579bool RegExpMacroAssemblerX64::CheckCharacterNotInRangeArray(
580 const ZoneList<CharacterRange>* ranges, Label* on_not_in_range) {
581 CallIsCharacterInRangeArray(ranges);
583 BranchOrBacktrack(zero, on_not_in_range);
587void RegExpMacroAssemblerX64::CheckBitInTable(
588 Handle<ByteArray> table,
591 Register index = current_character();
592 if (
mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) {
593 __ movq(rbx, current_character());
594 __ andq(rbx, Immediate(kTableMask));
599 BranchOrBacktrack(not_equal, on_bit_set);
602void RegExpMacroAssemblerX64::SkipUntilBitInTable(
603 int cp_offset, Handle<ByteArray> table,
604 Handle<ByteArray> nibble_table_array,
int advance_by) {
605 Label cont, scalar_repeat;
607 const bool use_simd = SkipUntilBitInTableUseSimd(advance_by);
609 DCHECK(!nibble_table_array.is_null());
610 Label simd_repeat, found, scalar;
611 static constexpr int kVectorSize = 16;
612 const int kCharsPerVector = kVectorSize / char_size();
619 CheckPosition(cp_offset + kCharsPerVector - 1, &scalar);
624 XMMRegister nibble_table = xmm0;
625 __ Move(r11, nibble_table_array);
627 XMMRegister nibble_mask = xmm1;
628 __ Move(r11, 0x0f0f0f0f'0f0f0f0f);
629 __ movq(nibble_mask, r11);
630 __ Movddup(nibble_mask, nibble_mask);
631 XMMRegister hi_nibble_lookup_mask = xmm2;
632 __ Move(r11, 0x80402010'08040201);
633 __ movq(hi_nibble_lookup_mask, r11);
634 __ Movddup(hi_nibble_lookup_mask, hi_nibble_lookup_mask);
638 XMMRegister input_vec = xmm3;
639 __ Movdqu(input_vec, Operand(rsi, rdi, times_1, cp_offset));
643 XMMRegister lo_nibbles = xmm4;
644 if (CpuFeatures::IsSupported(AVX)) {
645 __ Andps(lo_nibbles, nibble_mask, input_vec);
647 __ Movdqa(lo_nibbles, nibble_mask);
648 __ Andps(lo_nibbles, lo_nibbles, input_vec);
652 __ Psrlw(input_vec, uint8_t{4});
654 __ Andps(hi_nibbles, hi_nibbles, nibble_mask);
658 XMMRegister row = xmm5;
659 __ Pshufb(row, nibble_table, lo_nibbles);
667 __ Pshufb(bitmask, hi_nibble_lookup_mask, hi_nibbles);
678 __ j(not_zero, &found);
682 AdvanceCurrentPosition(kCharsPerVector);
683 CheckPosition(cp_offset + kCharsPerVector - 1, &scalar);
684 __ jmp(&simd_repeat);
694 __ andl(r11, Immediate(0xfffe));
703 __ Move(table_reg, table);
705 Bind(&scalar_repeat);
706 CheckPosition(cp_offset, &cont);
707 LoadCurrentCharacterUnchecked(cp_offset, 1);
708 Register index = current_character();
709 if (
mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) {
711 __ movq(index, current_character());
712 __ andq(index, Immediate(kTableMask));
717 __ j(not_equal, &cont);
718 AdvanceCurrentPosition(advance_by);
719 __ jmp(&scalar_repeat);
724bool RegExpMacroAssemblerX64::SkipUntilBitInTableUseSimd(
int advance_by) {
730 return v8_flags.regexp_simd && advance_by * char_size() == 1 &&
731 CpuFeatures::IsSupported(SSSE3);
734bool RegExpMacroAssemblerX64::CheckSpecialClassRanges(StandardCharacterSet type,
735 Label* on_no_match) {
742 case StandardCharacterSet::kWhitespace:
744 if (
mode_ == LATIN1) {
747 __ cmpl(current_character(), Immediate(
' '));
748 __ j(equal, &success, Label::kNear);
750 __ leal(rax, Operand(current_character(), -
'\t'));
751 __ cmpl(rax, Immediate(
'\r' -
'\t'));
752 __ j(below_equal, &success, Label::kNear);
754 __ cmpl(rax, Immediate(0x00A0 -
'\t'));
755 BranchOrBacktrack(not_equal, on_no_match);
760 case StandardCharacterSet::kNotWhitespace:
763 case StandardCharacterSet::kDigit:
765 __ leal(rax, Operand(current_character(), -
'0'));
766 __ cmpl(rax, Immediate(
'9' -
'0'));
767 BranchOrBacktrack(above, on_no_match);
769 case StandardCharacterSet::kNotDigit:
771 __ leal(rax, Operand(current_character(), -
'0'));
772 __ cmpl(rax, Immediate(
'9' -
'0'));
773 BranchOrBacktrack(below_equal, on_no_match);
775 case StandardCharacterSet::kNotLineTerminator: {
777 __ movl(rax, current_character());
778 __ xorl(rax, Immediate(0x01));
780 __ subl(rax, Immediate(0x0B));
781 __ cmpl(rax, Immediate(0x0C - 0x0B));
782 BranchOrBacktrack(below_equal, on_no_match);
787 __ subl(rax, Immediate(0x2028 - 0x0B));
788 __ cmpl(rax, Immediate(0x2029 - 0x2028));
789 BranchOrBacktrack(below_equal, on_no_match);
793 case StandardCharacterSet::kLineTerminator: {
795 __ movl(rax, current_character());
796 __ xorl(rax, Immediate(0x01));
798 __ subl(rax, Immediate(0x0B));
799 __ cmpl(rax, Immediate(0x0C - 0x0B));
800 if (
mode_ == LATIN1) {
801 BranchOrBacktrack(above, on_no_match);
804 BranchOrBacktrack(below_equal, &done);
808 __ subl(rax, Immediate(0x2028 - 0x0B));
809 __ cmpl(rax, Immediate(0x2029 - 0x2028));
810 BranchOrBacktrack(above, on_no_match);
815 case StandardCharacterSet::kWord: {
816 if (
mode_ != LATIN1) {
818 __ cmpl(current_character(), Immediate(
'z'));
819 BranchOrBacktrack(above, on_no_match);
821 __ Move(rbx, ExternalReference::re_word_character_map());
823 word_character_map[0]);
824 __ testb(Operand(rbx, current_character(), times_1, 0),
825 current_character());
826 BranchOrBacktrack(zero, on_no_match);
829 case StandardCharacterSet::kNotWord: {
831 if (
mode_ != LATIN1) {
833 __ cmpl(current_character(), Immediate(
'z'));
836 __ Move(rbx, ExternalReference::re_word_character_map());
838 word_character_map[0]);
839 __ testb(Operand(rbx, current_character(), times_1, 0),
840 current_character());
841 BranchOrBacktrack(not_zero, on_no_match);
842 if (
mode_ != LATIN1) {
848 case StandardCharacterSet::kEverything:
854void RegExpMacroAssemblerX64::BindJumpTarget(Label*
label) {
860void RegExpMacroAssemblerX64::Fail() {
863 __ Move(rax, FAILURE);
865 __ jmp(&exit_label_);
868void RegExpMacroAssemblerX64::LoadRegExpStackPointerFromMemory(Register dst) {
869 ExternalReference ref =
870 ExternalReference::address_of_regexp_stack_stack_pointer(
isolate());
871 __ movq(dst,
__ ExternalReferenceAsOperand(ref, dst));
874void RegExpMacroAssemblerX64::StoreRegExpStackPointerToMemory(
875 Register src, Register scratch) {
876 ExternalReference ref =
877 ExternalReference::address_of_regexp_stack_stack_pointer(
isolate());
878 __ movq(
__ ExternalReferenceAsOperand(ref, scratch), src);
881void RegExpMacroAssemblerX64::PushRegExpBasePointer(Register stack_pointer,
883 ExternalReference ref =
884 ExternalReference::address_of_regexp_stack_memory_top_address(
isolate());
885 __ movq(scratch,
__ ExternalReferenceAsOperand(ref, scratch));
886 __ subq(scratch, stack_pointer);
887 __ movq(Operand(rbp, kRegExpStackBasePointerOffset), scratch);
890void RegExpMacroAssemblerX64::PopRegExpBasePointer(Register stack_pointer_out,
892 ExternalReference ref =
893 ExternalReference::address_of_regexp_stack_memory_top_address(
isolate());
894 __ movq(scratch, Operand(rbp, kRegExpStackBasePointerOffset));
895 __ movq(stack_pointer_out,
896 __ ExternalReferenceAsOperand(ref, stack_pointer_out));
897 __ subq(stack_pointer_out, scratch);
898 StoreRegExpStackPointerToMemory(stack_pointer_out, scratch);
901DirectHandle<HeapObject> RegExpMacroAssemblerX64::GetCode(
902 DirectHandle<String> source, RegExpFlags flags) {
906 __ bind(&entry_label_);
910 FrameScope scope(&
masm_, StackFrame::MANUAL);
915 __ EnterFrame(StackFrame::IRREGEXP);
919#ifdef V8_TARGET_OS_WIN
922 __ movq(Operand(rbp, kInputStringOffset), kCArgRegs[0]);
923 __ movq(Operand(rbp, kStartIndexOffset),
925 __ movq(Operand(rbp, kInputStartOffset), kCArgRegs[2]);
926 __ movq(Operand(rbp, kInputEndOffset), kCArgRegs[3]);
928 static_assert(kNumCalleeSaveRegisters == 3);
944 __ pushq(kCArgRegs[0]);
945 __ pushq(kCArgRegs[1]);
946 __ pushq(kCArgRegs[2]);
947 __ pushq(kCArgRegs[3]);
951 static_assert(kNumCalleeSaveRegisters == 1);
956 static_assert(kSuccessfulCapturesOffset ==
958 __ Push(Immediate(0));
959 static_assert(kStringStartMinusOneOffset ==
961 __ Push(Immediate(0));
962 static_assert(kBacktrackCountOffset ==
964 __ Push(Immediate(0));
965 static_assert(kRegExpStackBasePointerOffset ==
967 __ Push(Immediate(0));
971 static_assert(backtrack_stackpointer() == rcx);
972 LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
976 PushRegExpBasePointer(backtrack_stackpointer(), kScratchRegister);
980 Label stack_limit_hit, stack_ok;
982 ExternalReference stack_limit =
983 ExternalReference::address_of_jslimit(
isolate());
985 __ Move(kScratchRegister, stack_limit);
986 __ subq(r9, Operand(kScratchRegister, 0));
987 Immediate extra_space_for_variables(num_registers_ * kSystemPointerSize);
990 __ j(below_equal, &stack_limit_hit);
993 __ cmpq(r9, extra_space_for_variables);
994 __ j(above_equal, &stack_ok);
997 __ Move(rax, EXCEPTION);
1000 __ bind(&stack_limit_hit);
1001 __ Move(code_object_pointer(),
masm_.CodeObject());
1002 __ pushq(backtrack_stackpointer());
1004 CallCheckStackGuardState(extra_space_for_variables);
1005 __ popq(backtrack_stackpointer());
1008 __ j(not_zero, &return_rax);
1014 __ AllocateStackSpace(num_registers_ * kSystemPointerSize);
1016 __ movq(rsi, Operand(rbp, kInputEndOffset));
1018 __ movq(rdi, Operand(rbp, kInputStartOffset));
1023 __ movq(rbx, Operand(rbp, kStartIndexOffset));
1025 __ leaq(rax, Operand(rdi, rbx, CharSizeScaleFactor(), -char_size()));
1028 __ movq(Operand(rbp, kStringStartMinusOneOffset), rax);
1031 __ Move(code_object_pointer(),
masm_.CodeObject());
1033 Label load_char_start_regexp;
1038 __ cmpl(Operand(rbp, kStartIndexOffset), Immediate(0));
1039 __ j(not_equal, &load_char_start_regexp, Label::kNear);
1040 __ Move(current_character(),
'\n');
1041 __ jmp(&start_regexp, Label::kNear);
1044 __ bind(&load_char_start_regexp);
1046 LoadCurrentCharacterUnchecked(-1, 1);
1048 __ bind(&start_regexp);
1052 if (num_saved_registers_ > 0) {
1056 if (num_saved_registers_ > 8) {
1057 __ Move(r9, kRegisterZeroOffset);
1059 __ bind(&init_loop);
1060 __ movq(Operand(rbp, r9, times_1, 0), rax);
1061 __ subq(r9, Immediate(kSystemPointerSize));
1062 __ cmpq(r9, Immediate(kRegisterZeroOffset -
1063 num_saved_registers_ * kSystemPointerSize));
1064 __ j(greater, &init_loop);
1066 for (
int i = 0;
i < num_saved_registers_;
i++) {
1067 __ movq(register_location(
i), rax);
1072 __ jmp(&start_label_);
1075 if (success_label_.is_linked()) {
1077 __ bind(&success_label_);
1078 if (num_saved_registers_ > 0) {
1080 __ movq(rdx, Operand(rbp, kStartIndexOffset));
1081 __ movq(rbx, Operand(rbp, kRegisterOutputOffset));
1082 __ movq(rcx, Operand(rbp, kInputEndOffset));
1083 __ subq(rcx, Operand(rbp, kInputStartOffset));
1084 if (
mode_ == UC16) {
1085 __ leaq(rcx, Operand(rcx, rdx, CharSizeScaleFactor(), 0));
1089 for (
int i = 0;
i < num_saved_registers_;
i++) {
1090 __ movq(rax, register_location(
i));
1091 if (
i == 0 && global_with_zero_length_check()) {
1096 if (
mode_ == UC16) {
1097 __ sarq(rax, Immediate(1));
1099 __ movl(Operand(rbx,
i * kIntSize), rax);
1106 __ incq(Operand(rbp, kSuccessfulCapturesOffset));
1109 __ movsxlq(rcx, Operand(rbp, kNumOutputRegistersOffset));
1110 __ subq(rcx, Immediate(num_saved_registers_));
1112 __ cmpq(rcx, Immediate(num_saved_registers_));
1113 __ j(less, &exit_label_);
1115 __ movq(Operand(rbp, kNumOutputRegistersOffset), rcx);
1117 __ addq(Operand(rbp, kRegisterOutputOffset),
1118 Immediate(num_saved_registers_ * kIntSize));
1122 PopRegExpBasePointer(backtrack_stackpointer(), kScratchRegister);
1124 Label reload_string_start_minus_one;
1126 if (global_with_zero_length_check()) {
1131 __ j(not_equal, &reload_string_start_minus_one);
1134 __ j(zero, &exit_label_, Label::kNear);
1138 if (
mode_ == UC16) {
1139 __ addq(rdi, Immediate(2));
1143 if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
1146 __ bind(&reload_string_start_minus_one);
1149 __ movq(rax, Operand(rbp, kStringStartMinusOneOffset));
1151 __ jmp(&load_char_start_regexp);
1153 __ Move(rax, SUCCESS);
1157 __ bind(&exit_label_);
1160 __ movq(rax, Operand(rbp, kSuccessfulCapturesOffset));
1163 __ bind(&return_rax);
1166 PopRegExpBasePointer(backtrack_stackpointer(), kScratchRegister);
1168#ifdef V8_TARGET_OS_WIN
1170 __ leaq(rsp, Operand(rbp, kLastCalleeSaveRegister));
1171 static_assert(kNumCalleeSaveRegisters == 3);
1180 static_assert(kNumCalleeSaveRegisters == 1);
1181 __ movq(rbx, Operand(rbp, kBackupRbxOffset));
1184 __ LeaveFrame(StackFrame::IRREGEXP);
1188 if (backtrack_label_.is_linked()) {
1189 __ bind(&backtrack_label_);
1193 Label exit_with_exception;
1196 if (check_preempt_label_.is_linked()) {
1197 SafeCallTarget(&check_preempt_label_);
1201 StoreRegExpStackPointerToMemory(backtrack_stackpointer(), kScratchRegister);
1203 CallCheckStackGuardState();
1207 __ j(not_zero, &return_rax);
1210 __ Move(code_object_pointer(),
masm_.CodeObject());
1213 LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
1216 __ movq(rsi, Operand(rbp, kInputEndOffset));
1221 if (stack_overflow_label_.is_linked()) {
1222 SafeCallTarget(&stack_overflow_label_);
1225 PushCallerSavedRegisters();
1229 StoreRegExpStackPointerToMemory(backtrack_stackpointer(), kScratchRegister);
1231 static constexpr int kNumArguments = 1;
1232 __ PrepareCallCFunction(kNumArguments);
1233 __ LoadAddress(kCArgRegs[0], ExternalReference::isolate_address(
isolate()));
1235 ExternalReference
grow_stack = ExternalReference::re_grow_stack();
1236 CallCFunctionFromIrregexpCode(grow_stack, kNumArguments);
1240 __ j(equal, &exit_with_exception);
1241 PopCallerSavedRegisters();
1243 __ movq(backtrack_stackpointer(), rax);
1245 __ Move(code_object_pointer(),
masm_.CodeObject());
1249 if (exit_with_exception.is_linked()) {
1251 __ bind(&exit_with_exception);
1253 __ Move(rax, EXCEPTION);
1254 __ jmp(&return_rax);
1257 if (fallback_label_.is_linked()) {
1258 __ bind(&fallback_label_);
1259 __ Move(rax, FALLBACK_TO_EXPERIMENTAL);
1260 __ jmp(&return_rax);
1263 FixupCodeRelativePositions();
1266 Isolate* isolate = this->
isolate();
1268 DirectHandle<Code> code =
1269 Factory::CodeBuilder(isolate,
code_desc, CodeKind::REGEXP)
1270 .set_self_reference(
masm_.CodeObject())
1271 .set_empty_source_position_table()
1274 RegExpCodeCreateEvent(Cast<AbstractCode>(code), source, flags));
1275 return Cast<HeapObject>(code);
1278void RegExpMacroAssemblerX64::GoTo(Label* to) { BranchOrBacktrack(to); }
1280void RegExpMacroAssemblerX64::IfRegisterGE(
int reg,
1283 __ cmpq(register_location(
reg), Immediate(comparand));
1284 BranchOrBacktrack(greater_equal, if_ge);
1288void RegExpMacroAssemblerX64::IfRegisterLT(
int reg,
1291 __ cmpq(register_location(
reg), Immediate(comparand));
1292 BranchOrBacktrack(less, if_lt);
1296void RegExpMacroAssemblerX64::IfRegisterEqPos(
int reg,
1298 __ cmpq(rdi, register_location(
reg));
1299 BranchOrBacktrack(equal, if_eq);
1303RegExpMacroAssembler::IrregexpImplementation
1304 RegExpMacroAssemblerX64::Implementation() {
1305 return kX64Implementation;
1309void RegExpMacroAssemblerX64::PopCurrentPosition() {
1314void RegExpMacroAssemblerX64::PopRegister(
int register_index) {
1316 __ movq(register_location(register_index), rax);
1320void RegExpMacroAssemblerX64::PushBacktrack(Label*
label) {
1326void RegExpMacroAssemblerX64::PushCurrentPosition() {
1332void RegExpMacroAssemblerX64::PushRegister(
int register_index,
1333 StackCheckFlag check_stack_limit) {
1334 __ movq(rax, register_location(register_index));
1336 if (check_stack_limit) {
1339 AssertAboveStackLimitMinusSlack();
1343void RegExpMacroAssemblerX64::ReadCurrentPositionFromRegister(
int reg) {
1344 __ movq(rdi, register_location(
reg));
1348void RegExpMacroAssemblerX64::ReadPositionFromRegister(Register dst,
int reg) {
1349 __ movq(dst, register_location(
reg));
1354void RegExpMacroAssemblerX64::WriteStackPointerToRegister(
int reg) {
1355 ExternalReference stack_top_address =
1356 ExternalReference::address_of_regexp_stack_memory_top_address(
isolate());
1357 __ movq(rax,
__ ExternalReferenceAsOperand(stack_top_address, rax));
1358 __ subq(rax, backtrack_stackpointer());
1359 __ movq(register_location(
reg), rax);
1362void RegExpMacroAssemblerX64::ReadStackPointerFromRegister(
int reg) {
1363 ExternalReference stack_top_address =
1364 ExternalReference::address_of_regexp_stack_memory_top_address(
isolate());
1365 __ movq(backtrack_stackpointer(),
1366 __ ExternalReferenceAsOperand(stack_top_address,
1367 backtrack_stackpointer()));
1368 __ subq(backtrack_stackpointer(), register_location(
reg));
1371void RegExpMacroAssemblerX64::SetCurrentPositionFromEnd(
int by) {
1372 Label after_position;
1373 __ cmpq(rdi, Immediate(-by * char_size()));
1374 __ j(greater_equal, &after_position, Label::kNear);
1375 __ Move(rdi, -by * char_size());
1379 LoadCurrentCharacterUnchecked(-1, 1);
1380 __ bind(&after_position);
1384void RegExpMacroAssemblerX64::SetRegister(
int register_index,
int to) {
1385 DCHECK(register_index >= num_saved_registers_);
1386 __ movq(register_location(register_index), Immediate(to));
1390bool RegExpMacroAssemblerX64::Succeed() {
1391 __ jmp(&success_label_);
1396void RegExpMacroAssemblerX64::WriteCurrentPositionToRegister(
int reg,
1398 if (cp_offset == 0) {
1399 __ movq(register_location(
reg), rdi);
1401 __ leaq(rax, Operand(rdi, cp_offset * char_size()));
1402 __ movq(register_location(
reg), rax);
1407void RegExpMacroAssemblerX64::ClearRegisters(
int reg_from,
int reg_to) {
1408 DCHECK(reg_from <= reg_to);
1409 __ movq(rax, Operand(rbp, kStringStartMinusOneOffset));
1410 for (
int reg = reg_from;
reg <= reg_to;
reg++) {
1411 __ movq(register_location(
reg), rax);
1417void RegExpMacroAssemblerX64::CallCheckStackGuardState(Immediate extra_space) {
1420 static const int num_arguments = 4;
1421 __ PrepareCallCFunction(num_arguments);
1422#ifdef V8_TARGET_OS_WIN
1424 __ movq(kCArgRegs[3], extra_space);
1427 __ movq(kCArgRegs[1], code_object_pointer());
1429 __ movq(kCArgRegs[2], rbp);
1432 __ leaq(kCArgRegs[0], Operand(rsp, -kSystemPointerSize));
1435 __ movq(kCArgRegs[3], extra_space);
1437 __ movq(kCArgRegs[2], rbp);
1439 __ movq(kCArgRegs[1], code_object_pointer());
1442 __ leaq(kCArgRegs[0], Operand(rsp, -kSystemPointerSize));
1444 ExternalReference stack_check =
1445 ExternalReference::re_check_stack_guard_state();
1446 CallCFunctionFromIrregexpCode(stack_check, num_arguments);
1450template <
typename T>
1451static T& frame_entry(Address re_frame,
int frame_offset) {
1452 return reinterpret_cast<T&
>(Memory<int32_t>(re_frame + frame_offset));
1456template <
typename T>
1457static T* frame_entry_address(Address re_frame,
int frame_offset) {
1458 return reinterpret_cast<T*
>(re_frame + frame_offset);
1461int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
1464 uintptr_t extra_space) {
1465 Tagged<InstructionStream> re_code =
1466 Cast<InstructionStream>(Tagged<Object>(raw_code));
1467 return NativeRegExpMacroAssembler::CheckStackGuardState(
1468 frame_entry<Isolate*>(re_frame, kIsolateOffset),
1469 frame_entry<int>(re_frame, kStartIndexOffset),
1470 static_cast<RegExp::CallOrigin
>(
1471 frame_entry<int>(re_frame, kDirectCallOffset)),
1472 return_address, re_code,
1473 frame_entry_address<Address>(re_frame, kInputStringOffset),
1474 frame_entry_address<const uint8_t*>(re_frame, kInputStartOffset),
1475 frame_entry_address<const uint8_t*>(re_frame, kInputEndOffset),
1479Operand RegExpMacroAssemblerX64::register_location(
int register_index) {
1480 DCHECK(register_index < (1<<30));
1481 if (num_registers_ <= register_index) {
1482 num_registers_ = register_index + 1;
1485 kRegisterZeroOffset - register_index * kSystemPointerSize);
1489void RegExpMacroAssemblerX64::CheckPosition(
int cp_offset,
1490 Label* on_outside_input) {
1491 if (cp_offset >= 0) {
1492 __ cmpl(rdi, Immediate(-cp_offset * char_size()));
1493 BranchOrBacktrack(greater_equal, on_outside_input);
1495 __ leaq(rax, Operand(rdi, cp_offset * char_size()));
1496 __ cmpq(rax, Operand(rbp, kStringStartMinusOneOffset));
1497 BranchOrBacktrack(less_equal, on_outside_input);
1501void RegExpMacroAssemblerX64::BranchOrBacktrack(Label* to) {
1502 if (to ==
nullptr) {
1509void RegExpMacroAssemblerX64::BranchOrBacktrack(Condition
condition,
1514void RegExpMacroAssemblerX64::SafeCall(Label* to) {
1519void RegExpMacroAssemblerX64::SafeCallTarget(Label*
label) {
1521 __ subq(Operand(rsp, 0), code_object_pointer());
1525void RegExpMacroAssemblerX64::SafeReturn() {
1526 __ addq(Operand(rsp, 0), code_object_pointer());
1531void RegExpMacroAssemblerX64::Push(Register source) {
1532 DCHECK(source != backtrack_stackpointer());
1534 __ subq(backtrack_stackpointer(), Immediate(kIntSize));
1535 __ movl(Operand(backtrack_stackpointer(), 0), source);
1539void RegExpMacroAssemblerX64::Push(Immediate value) {
1541 __ subq(backtrack_stackpointer(), Immediate(kIntSize));
1542 __ movl(Operand(backtrack_stackpointer(), 0), value);
1546void RegExpMacroAssemblerX64::FixupCodeRelativePositions() {
1547 for (
int position : code_relative_fixup_positions_) {
1555 offset +
position + InstructionStream::kHeaderSize - kHeapObjectTag);
1557 code_relative_fixup_positions_.Rewind(0);
1561void RegExpMacroAssemblerX64::Push(Label* backtrack_target) {
1562 __ subq(backtrack_stackpointer(), Immediate(kIntSize));
1563 __ movl(Operand(backtrack_stackpointer(), 0), backtrack_target);
1564 MarkPositionForCodeRelativeFixup();
1568void RegExpMacroAssemblerX64::Pop(Register target) {
1569 DCHECK(target != backtrack_stackpointer());
1570 __ movsxlq(target, Operand(backtrack_stackpointer(), 0));
1572 __ addq(backtrack_stackpointer(), Immediate(kIntSize));
1576void RegExpMacroAssemblerX64::Drop() {
1577 __ addq(backtrack_stackpointer(), Immediate(kIntSize));
1581void RegExpMacroAssemblerX64::CheckPreemption() {
1584 ExternalReference stack_limit =
1585 ExternalReference::address_of_jslimit(
isolate());
1586 __ load_rax(stack_limit);
1588 __ j(above, &no_preempt);
1590 SafeCall(&check_preempt_label_);
1592 __ bind(&no_preempt);
1596void RegExpMacroAssemblerX64::CheckStackLimit() {
1597 Label no_stack_overflow;
1598 ExternalReference stack_limit =
1599 ExternalReference::address_of_regexp_stack_limit_address(
isolate());
1600 __ load_rax(stack_limit);
1601 __ cmpq(backtrack_stackpointer(), rax);
1602 __ j(above, &no_stack_overflow);
1604 SafeCall(&stack_overflow_label_);
1606 __ bind(&no_stack_overflow);
1609void RegExpMacroAssemblerX64::AssertAboveStackLimitMinusSlack() {
1611 Label no_stack_overflow;
1613 auto l = ExternalReference::address_of_regexp_stack_limit_address(
isolate());
1615 __ subq(rax, Immediate(RegExpStack::kStackLimitSlackSize));
1616 __ cmpq(backtrack_stackpointer(), rax);
1617 __ j(above, &no_stack_overflow);
1619 __ bind(&no_stack_overflow);
1622void RegExpMacroAssemblerX64::LoadCurrentCharacterUnchecked(
int cp_offset,
1624 if (
mode_ == LATIN1) {
1625 if (characters == 4) {
1626 __ movl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1627 }
else if (characters == 2) {
1628 __ movzxwl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1631 __ movzxbl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1635 if (characters == 2) {
1636 __ movl(current_character(),
1637 Operand(rsi, rdi, times_1, cp_offset *
sizeof(base::uc16)));
1640 __ movzxwl(current_character(),
1641 Operand(rsi, rdi, times_1, cp_offset *
sizeof(base::uc16)));
RegExpMacroAssemblerX64(Isolate *isolate, Zone *zone, Mode mode, int registers_to_save)
static constexpr int kRegExpCodeSize
#define PROFILE(the_isolate, Call)
RecordWriteMode const mode_
const CodeDesc * code_desc
#define ASM_CODE_COMMENT_STRING(asm,...)
ZoneVector< RpoNumber > & result
MaglevAssembler *const masm_
Address grow_stack(Isolate *isolate, void *current_sp, size_t frame_size, size_t gap, Address current_fp)
Operand FieldOperand(Register object, int offset)
constexpr int kSystemPointerSize
std::unique_ptr< AssemblerBuffer > NewAssemblerBuffer(int size)
V8_EXPORT_PRIVATE FlagValues v8_flags
Register ReassignRegister(Register &source)
#define DCHECK_LE(v1, v2)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)
#define DCHECK_GT(v1, v2)
#define OFFSET_OF_DATA_START(Type)
#define V8_UNLIKELY(condition)