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
3 // found in the LICENSE file.
7 #if V8_TARGET_ARCH_ARM64
9 #include "cpu-profiler.h"
12 #include "code-stubs.h"
13 #include "regexp-stack.h"
14 #include "macro-assembler.h"
15 #include "regexp-macro-assembler.h"
16 #include "arm64/regexp-macro-assembler-arm64.h"
21 #ifndef V8_INTERPRETED_REGEXP
23 * This assembler uses the following register assignment convention:
24 * - w19 : Used to temporarely store a value before a call to C code.
25 * See CheckNotBackReferenceIgnoreCase.
26 * - x20 : Pointer to the current code object (Code*),
27 * it includes the heap object tag.
28 * - w21 : Current position in input, as negative offset from
29 * the end of the string. Please notice that this is
30 * the byte offset, not the character offset!
31 * - w22 : Currently loaded character. Must be loaded using
32 * LoadCurrentCharacter before using any of the dispatch methods.
33 * - x23 : Points to tip of backtrack stack.
34 * - w24 : Position of the first character minus one: non_position_value.
35 * Used to initialize capture registers.
36 * - x25 : Address at the end of the input string: input_end.
37 * Points to byte after last character in input.
38 * - x26 : Address at the start of the input string: input_start.
39 * - w27 : Where to start in the input string.
40 * - x28 : Output array pointer.
41 * - x29/fp : Frame pointer. Used to access arguments, local variables and
43 * - x16/x17 : IP registers, used by assembler. Very volatile.
44 * - csp : Points to tip of C stack.
46 * - x0-x7 : Used as a cache to store 32 bit capture registers. These
47 * registers need to be retained every time a call to C code
50 * The remaining registers are free for computations.
51 * Each call to a public method should retain this convention.
53 * The stack will have the following structure:
55 * Location Name Description
59 * - fp[104] isolate Address of the current isolate.
60 * - fp[96] return_address Secondary link/return address
61 * used by an exit frame if this is a
63 * ^^^ csp when called ^^^
64 * - fp[88] lr Return from the RegExp code.
65 * - fp[80] r29 Old frame pointer (CalleeSaved).
66 * - fp[0..72] r19-r28 Backup of CalleeSaved registers.
67 * - fp[-8] direct_call 1 => Direct call from JavaScript code.
68 * 0 => Call through the runtime system.
69 * - fp[-16] stack_base High end of the memory area to use as
70 * the backtracking stack.
71 * - fp[-24] output_size Output may fit multiple sets of matches.
72 * - fp[-32] input Handle containing the input string.
73 * - fp[-40] success_counter
74 * ^^^^^^^^^^^^^ From here and downwards we store 32 bit values ^^^^^^^^^^^^^
75 * - fp[-44] register N Capture registers initialized with
76 * - fp[-48] register N + 1 non_position_value.
77 * ... The first kNumCachedRegisters (N) registers
78 * ... are cached in x0 to x7.
79 * ... Only positions must be stored in the first
80 * - ... num_saved_registers_ registers.
82 * - register N + num_registers - 1
83 * ^^^^^^^^^ csp ^^^^^^^^^
85 * The first num_saved_registers_ registers are initialized to point to
86 * "character -1" in the string (i.e., char_size() bytes before the first
87 * character of the string). The remaining registers start out as garbage.
89 * The data up to the return address must be placed there by the calling
90 * code and the remaining arguments are passed in registers, e.g. by calling the
91 * code entry as cast to a function with the signature:
92 * int (*match)(String* input,
94 * Address input_start,
99 * bool direct_call = false,
100 * Address secondary_return_address, // Only used by native call.
102 * The call is performed by NativeRegExpMacroAssembler::Execute()
103 * (in regexp-macro-assembler.cc) via the CALL_GENERATED_REGEXP_CODE macro
104 * in arm64/simulator-arm64.h.
105 * When calling as a non-direct call (i.e., from C++ code), the return address
106 * area is overwritten with the LR register by the RegExp code. When doing a
107 * direct call from generated code, the return address is placed there by
108 * the calling code, as in a normal exit frame.
111 #define __ ACCESS_MASM(masm_)
113 RegExpMacroAssemblerARM64::RegExpMacroAssemblerARM64(
115 int registers_to_save,
117 : NativeRegExpMacroAssembler(zone),
118 masm_(new MacroAssembler(zone->isolate(), NULL, kRegExpCodeSize)),
120 num_registers_(registers_to_save),
121 num_saved_registers_(registers_to_save),
127 __ SetStackPointer(csp);
128 ASSERT_EQ(0, registers_to_save % 2);
129 // We can cache at most 16 W registers in x0-x7.
130 STATIC_ASSERT(kNumCachedRegisters <= 16);
131 STATIC_ASSERT((kNumCachedRegisters % 2) == 0);
132 __ B(&entry_label_); // We'll write the entry code later.
133 __ Bind(&start_label_); // And then continue from here.
137 RegExpMacroAssemblerARM64::~RegExpMacroAssemblerARM64() {
139 // Unuse labels in case we throw away the assembler without calling GetCode.
140 entry_label_.Unuse();
141 start_label_.Unuse();
142 success_label_.Unuse();
143 backtrack_label_.Unuse();
145 check_preempt_label_.Unuse();
146 stack_overflow_label_.Unuse();
149 int RegExpMacroAssemblerARM64::stack_limit_slack() {
150 return RegExpStack::kStackLimitSlack;
154 void RegExpMacroAssemblerARM64::AdvanceCurrentPosition(int by) {
156 __ Add(current_input_offset(),
157 current_input_offset(), by * char_size());
162 void RegExpMacroAssemblerARM64::AdvanceRegister(int reg, int by) {
163 ASSERT((reg >= 0) && (reg < num_registers_));
166 RegisterState register_state = GetRegisterState(reg);
167 switch (register_state) {
169 __ Ldr(w10, register_location(reg));
170 __ Add(w10, w10, by);
171 __ Str(w10, register_location(reg));
174 to_advance = GetCachedRegister(reg);
175 __ Add(to_advance, to_advance, by);
178 to_advance = GetCachedRegister(reg);
179 __ Add(to_advance, to_advance,
180 static_cast<int64_t>(by) << kWRegSizeInBits);
190 void RegExpMacroAssemblerARM64::Backtrack() {
193 __ Add(x10, code_pointer(), Operand(w10, UXTW));
198 void RegExpMacroAssemblerARM64::Bind(Label* label) {
203 void RegExpMacroAssemblerARM64::CheckCharacter(uint32_t c, Label* on_equal) {
204 CompareAndBranchOrBacktrack(current_character(), c, eq, on_equal);
208 void RegExpMacroAssemblerARM64::CheckCharacterGT(uc16 limit,
210 CompareAndBranchOrBacktrack(current_character(), limit, hi, on_greater);
214 void RegExpMacroAssemblerARM64::CheckAtStart(Label* on_at_start) {
216 // Did we start the match at the start of the input string?
217 CompareAndBranchOrBacktrack(start_offset(), 0, ne, ¬_at_start);
218 // If we did, are we still at the start of the input string?
219 __ Add(x10, input_end(), Operand(current_input_offset(), SXTW));
220 __ Cmp(x10, input_start());
221 BranchOrBacktrack(eq, on_at_start);
222 __ Bind(¬_at_start);
226 void RegExpMacroAssemblerARM64::CheckNotAtStart(Label* on_not_at_start) {
227 // Did we start the match at the start of the input string?
228 CompareAndBranchOrBacktrack(start_offset(), 0, ne, on_not_at_start);
229 // If we did, are we still at the start of the input string?
230 __ Add(x10, input_end(), Operand(current_input_offset(), SXTW));
231 __ Cmp(x10, input_start());
232 BranchOrBacktrack(ne, on_not_at_start);
236 void RegExpMacroAssemblerARM64::CheckCharacterLT(uc16 limit, Label* on_less) {
237 CompareAndBranchOrBacktrack(current_character(), limit, lo, on_less);
241 void RegExpMacroAssemblerARM64::CheckCharacters(Vector<const uc16> str,
244 bool check_end_of_string) {
245 // This method is only ever called from the cctests.
247 if (check_end_of_string) {
248 // Is last character of required match inside string.
249 CheckPosition(cp_offset + str.length() - 1, on_failure);
252 Register characters_address = x11;
254 __ Add(characters_address,
256 Operand(current_input_offset(), SXTW));
257 if (cp_offset != 0) {
258 __ Add(characters_address, characters_address, cp_offset * char_size());
261 for (int i = 0; i < str.length(); i++) {
262 if (mode_ == ASCII) {
263 __ Ldrb(w10, MemOperand(characters_address, 1, PostIndex));
264 ASSERT(str[i] <= String::kMaxOneByteCharCode);
266 __ Ldrh(w10, MemOperand(characters_address, 2, PostIndex));
268 CompareAndBranchOrBacktrack(w10, str[i], ne, on_failure);
273 void RegExpMacroAssemblerARM64::CheckGreedyLoop(Label* on_equal) {
274 __ Ldr(w10, MemOperand(backtrack_stackpointer()));
275 __ Cmp(current_input_offset(), w10);
277 __ Add(backtrack_stackpointer(),
278 backtrack_stackpointer(), Operand(x11, LSL, kWRegSizeLog2));
279 BranchOrBacktrack(eq, on_equal);
282 void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase(
284 Label* on_no_match) {
287 Register capture_start_offset = w10;
288 // Save the capture length in a callee-saved register so it will
289 // be preserved if we call a C helper.
290 Register capture_length = w19;
291 ASSERT(kCalleeSaved.IncludesAliasOf(capture_length));
293 // Find length of back-referenced capture.
294 ASSERT((start_reg % 2) == 0);
295 if (start_reg < kNumCachedRegisters) {
296 __ Mov(capture_start_offset.X(), GetCachedRegister(start_reg));
297 __ Lsr(x11, GetCachedRegister(start_reg), kWRegSizeInBits);
299 __ Ldp(w11, capture_start_offset, capture_location(start_reg, x10));
301 __ Sub(capture_length, w11, capture_start_offset); // Length to check.
302 // Succeed on empty capture (including no capture).
303 __ Cbz(capture_length, &fallthrough);
305 // Check that there are enough characters left in the input.
306 __ Cmn(capture_length, current_input_offset());
307 BranchOrBacktrack(gt, on_no_match);
309 if (mode_ == ASCII) {
314 Register capture_start_address = x12;
315 Register capture_end_addresss = x13;
316 Register current_position_address = x14;
318 __ Add(capture_start_address,
320 Operand(capture_start_offset, SXTW));
321 __ Add(capture_end_addresss,
322 capture_start_address,
323 Operand(capture_length, SXTW));
324 __ Add(current_position_address,
326 Operand(current_input_offset(), SXTW));
330 __ Ldrb(w10, MemOperand(capture_start_address, 1, PostIndex));
331 __ Ldrb(w11, MemOperand(current_position_address, 1, PostIndex));
333 __ B(eq, &loop_check);
335 // Mismatch, try case-insensitive match (converting letters to lower-case).
336 __ Orr(w10, w10, 0x20); // Convert capture character to lower-case.
337 __ Orr(w11, w11, 0x20); // Also convert input character.
340 __ Sub(w10, w10, 'a');
341 __ Cmp(w10, 'z' - 'a'); // Is w10 a lowercase letter?
342 __ B(ls, &loop_check); // In range 'a'-'z'.
343 // Latin-1: Check for values in range [224,254] but not 247.
344 __ Sub(w10, w10, 224 - 'a');
345 __ Cmp(w10, 254 - 224);
346 __ Ccmp(w10, 247 - 224, ZFlag, ls); // Check for 247.
347 __ B(eq, &fail); // Weren't Latin-1 letters.
349 __ Bind(&loop_check);
350 __ Cmp(capture_start_address, capture_end_addresss);
355 BranchOrBacktrack(al, on_no_match);
358 // Compute new value of character position after the matched part.
359 __ Sub(current_input_offset().X(), current_position_address, input_end());
360 if (masm_->emit_debug_code()) {
361 __ Cmp(current_input_offset().X(), Operand(current_input_offset(), SXTW));
362 __ Ccmp(current_input_offset(), 0, NoFlag, eq);
363 // The current input offset should be <= 0, and fit in a W register.
364 __ Check(le, kOffsetOutOfRange);
367 ASSERT(mode_ == UC16);
368 int argument_count = 4;
370 // The cached registers need to be retained.
371 CPURegList cached_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 7);
372 ASSERT((cached_registers.Count() * 2) == kNumCachedRegisters);
373 __ PushCPURegList(cached_registers);
375 // Put arguments into arguments registers.
377 // x0: Address byte_offset1 - Address captured substring's start.
378 // x1: Address byte_offset2 - Address of current character position.
379 // w2: size_t byte_length - length of capture in bytes(!)
380 // x3: Isolate* isolate
382 // Address of start of capture.
383 __ Add(x0, input_end(), Operand(capture_start_offset, SXTW));
384 // Length of capture.
385 __ Mov(w2, capture_length);
386 // Address of current input position.
387 __ Add(x1, input_end(), Operand(current_input_offset(), SXTW));
389 __ Mov(x3, ExternalReference::isolate_address(isolate()));
392 AllowExternalCallThatCantCauseGC scope(masm_);
393 ExternalReference function =
394 ExternalReference::re_case_insensitive_compare_uc16(isolate());
395 __ CallCFunction(function, argument_count);
398 // Check if function returned non-zero for success or zero for failure.
399 CompareAndBranchOrBacktrack(x0, 0, eq, on_no_match);
400 // On success, increment position by length of capture.
401 __ Add(current_input_offset(), current_input_offset(), capture_length);
402 // Reset the cached registers.
403 __ PopCPURegList(cached_registers);
406 __ Bind(&fallthrough);
409 void RegExpMacroAssemblerARM64::CheckNotBackReference(
411 Label* on_no_match) {
414 Register capture_start_address = x12;
415 Register capture_end_address = x13;
416 Register current_position_address = x14;
417 Register capture_length = w15;
419 // Find length of back-referenced capture.
420 ASSERT((start_reg % 2) == 0);
421 if (start_reg < kNumCachedRegisters) {
422 __ Mov(x10, GetCachedRegister(start_reg));
423 __ Lsr(x11, GetCachedRegister(start_reg), kWRegSizeInBits);
425 __ Ldp(w11, w10, capture_location(start_reg, x10));
427 __ Sub(capture_length, w11, w10); // Length to check.
428 // Succeed on empty capture (including no capture).
429 __ Cbz(capture_length, &fallthrough);
431 // Check that there are enough characters left in the input.
432 __ Cmn(capture_length, current_input_offset());
433 BranchOrBacktrack(gt, on_no_match);
435 // Compute pointers to match string and capture string
436 __ Add(capture_start_address, input_end(), Operand(w10, SXTW));
437 __ Add(capture_end_address,
438 capture_start_address,
439 Operand(capture_length, SXTW));
440 __ Add(current_position_address,
442 Operand(current_input_offset(), SXTW));
446 if (mode_ == ASCII) {
447 __ Ldrb(w10, MemOperand(capture_start_address, 1, PostIndex));
448 __ Ldrb(w11, MemOperand(current_position_address, 1, PostIndex));
450 ASSERT(mode_ == UC16);
451 __ Ldrh(w10, MemOperand(capture_start_address, 2, PostIndex));
452 __ Ldrh(w11, MemOperand(current_position_address, 2, PostIndex));
455 BranchOrBacktrack(ne, on_no_match);
456 __ Cmp(capture_start_address, capture_end_address);
459 // Move current character position to position after match.
460 __ Sub(current_input_offset().X(), current_position_address, input_end());
461 if (masm_->emit_debug_code()) {
462 __ Cmp(current_input_offset().X(), Operand(current_input_offset(), SXTW));
463 __ Ccmp(current_input_offset(), 0, NoFlag, eq);
464 // The current input offset should be <= 0, and fit in a W register.
465 __ Check(le, kOffsetOutOfRange);
467 __ Bind(&fallthrough);
471 void RegExpMacroAssemblerARM64::CheckNotCharacter(unsigned c,
472 Label* on_not_equal) {
473 CompareAndBranchOrBacktrack(current_character(), c, ne, on_not_equal);
477 void RegExpMacroAssemblerARM64::CheckCharacterAfterAnd(uint32_t c,
480 __ And(w10, current_character(), mask);
481 CompareAndBranchOrBacktrack(w10, c, eq, on_equal);
485 void RegExpMacroAssemblerARM64::CheckNotCharacterAfterAnd(unsigned c,
487 Label* on_not_equal) {
488 __ And(w10, current_character(), mask);
489 CompareAndBranchOrBacktrack(w10, c, ne, on_not_equal);
493 void RegExpMacroAssemblerARM64::CheckNotCharacterAfterMinusAnd(
497 Label* on_not_equal) {
498 ASSERT(minus < String::kMaxUtf16CodeUnit);
499 __ Sub(w10, current_character(), minus);
500 __ And(w10, w10, mask);
501 CompareAndBranchOrBacktrack(w10, c, ne, on_not_equal);
505 void RegExpMacroAssemblerARM64::CheckCharacterInRange(
508 Label* on_in_range) {
509 __ Sub(w10, current_character(), from);
510 // Unsigned lower-or-same condition.
511 CompareAndBranchOrBacktrack(w10, to - from, ls, on_in_range);
515 void RegExpMacroAssemblerARM64::CheckCharacterNotInRange(
518 Label* on_not_in_range) {
519 __ Sub(w10, current_character(), from);
520 // Unsigned higher condition.
521 CompareAndBranchOrBacktrack(w10, to - from, hi, on_not_in_range);
525 void RegExpMacroAssemblerARM64::CheckBitInTable(
526 Handle<ByteArray> table,
528 __ Mov(x11, Operand(table));
529 if ((mode_ != ASCII) || (kTableMask != String::kMaxOneByteCharCode)) {
530 __ And(w10, current_character(), kTableMask);
531 __ Add(w10, w10, ByteArray::kHeaderSize - kHeapObjectTag);
533 __ Add(w10, current_character(), ByteArray::kHeaderSize - kHeapObjectTag);
535 __ Ldrb(w11, MemOperand(x11, w10, UXTW));
536 CompareAndBranchOrBacktrack(w11, 0, ne, on_bit_set);
540 bool RegExpMacroAssemblerARM64::CheckSpecialCharacterClass(uc16 type,
541 Label* on_no_match) {
542 // Range checks (c in min..max) are generally implemented by an unsigned
543 // (c - min) <= (max - min) check
546 // Match space-characters
547 if (mode_ == ASCII) {
548 // One byte space characters are '\t'..'\r', ' ' and \u00a0.
550 // Check for ' ' or 0x00a0.
551 __ Cmp(current_character(), ' ');
552 __ Ccmp(current_character(), 0x00a0, ZFlag, ne);
554 // Check range 0x09..0x0d.
555 __ Sub(w10, current_character(), '\t');
556 CompareAndBranchOrBacktrack(w10, '\r' - '\t', hi, on_no_match);
562 // The emitted code for generic character classes is good enough.
565 // Match ASCII digits ('0'..'9').
566 __ Sub(w10, current_character(), '0');
567 CompareAndBranchOrBacktrack(w10, '9' - '0', hi, on_no_match);
570 // Match ASCII non-digits.
571 __ Sub(w10, current_character(), '0');
572 CompareAndBranchOrBacktrack(w10, '9' - '0', ls, on_no_match);
575 // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
576 // Here we emit the conditional branch only once at the end to make branch
577 // prediction more efficient, even though we could branch out of here
578 // as soon as a character matches.
579 __ Cmp(current_character(), 0x0a);
580 __ Ccmp(current_character(), 0x0d, ZFlag, ne);
582 __ Sub(w10, current_character(), 0x2028);
583 // If the Z flag was set we clear the flags to force a branch.
584 __ Ccmp(w10, 0x2029 - 0x2028, NoFlag, ne);
585 // ls -> !((C==1) && (Z==0))
586 BranchOrBacktrack(ls, on_no_match);
588 BranchOrBacktrack(eq, on_no_match);
593 // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
594 // We have to check all 4 newline characters before emitting
595 // the conditional branch.
596 __ Cmp(current_character(), 0x0a);
597 __ Ccmp(current_character(), 0x0d, ZFlag, ne);
599 __ Sub(w10, current_character(), 0x2028);
600 // If the Z flag was set we clear the flags to force a fall-through.
601 __ Ccmp(w10, 0x2029 - 0x2028, NoFlag, ne);
602 // hi -> (C==1) && (Z==0)
603 BranchOrBacktrack(hi, on_no_match);
605 BranchOrBacktrack(ne, on_no_match);
610 if (mode_ != ASCII) {
611 // Table is 128 entries, so all ASCII characters can be tested.
612 CompareAndBranchOrBacktrack(current_character(), 'z', hi, on_no_match);
614 ExternalReference map = ExternalReference::re_word_character_map();
616 __ Ldrb(w10, MemOperand(x10, current_character(), UXTW));
617 CompareAndBranchOrBacktrack(w10, 0, eq, on_no_match);
622 if (mode_ != ASCII) {
623 // Table is 128 entries, so all ASCII characters can be tested.
624 __ Cmp(current_character(), 'z');
627 ExternalReference map = ExternalReference::re_word_character_map();
629 __ Ldrb(w10, MemOperand(x10, current_character(), UXTW));
630 CompareAndBranchOrBacktrack(w10, 0, ne, on_no_match);
635 // Match any character.
637 // No custom implementation (yet): s(UC16), S(UC16).
644 void RegExpMacroAssemblerARM64::Fail() {
650 Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
652 // Finalize code - write the entry point code now we know how many
653 // registers we need.
656 __ Bind(&entry_label_);
658 // Arguments on entry:
660 // x1: int start_offset
661 // x2: byte* input_start
662 // x3: byte* input_end
663 // x4: int* output array
664 // x5: int output array size
665 // x6: Address stack_base
666 // x7: int direct_call
668 // The stack pointer should be csp on entry.
669 // csp[8]: address of the current isolate
670 // csp[0]: secondary link/return address used by native call
672 // Tell the system that we have a stack frame. Because the type is MANUAL, no
673 // code is generated.
674 FrameScope scope(masm_, StackFrame::MANUAL);
676 // Push registers on the stack, only push the argument registers that we need.
677 CPURegList argument_registers(x0, x5, x6, x7);
679 CPURegList registers_to_retain = kCalleeSaved;
680 ASSERT(kCalleeSaved.Count() == 11);
681 registers_to_retain.Combine(lr);
683 ASSERT(csp.Is(__ StackPointer()));
684 __ PushCPURegList(registers_to_retain);
685 __ PushCPURegList(argument_registers);
687 // Set frame pointer in place.
688 __ Add(frame_pointer(), csp, argument_registers.Count() * kPointerSize);
690 // Initialize callee-saved registers.
691 __ Mov(start_offset(), w1);
692 __ Mov(input_start(), x2);
693 __ Mov(input_end(), x3);
694 __ Mov(output_array(), x4);
696 // Set the number of registers we will need to allocate, that is:
697 // - success_counter (X register)
698 // - (num_registers_ - kNumCachedRegisters) (W registers)
699 int num_wreg_to_allocate = num_registers_ - kNumCachedRegisters;
700 // Do not allocate registers on the stack if they can all be cached.
701 if (num_wreg_to_allocate < 0) { num_wreg_to_allocate = 0; }
702 // Make room for the success_counter.
703 num_wreg_to_allocate += 2;
705 // Make sure the stack alignment will be respected.
706 int alignment = masm_->ActivationFrameAlignment();
707 ASSERT_EQ(alignment % 16, 0);
708 int align_mask = (alignment / kWRegSize) - 1;
709 num_wreg_to_allocate = (num_wreg_to_allocate + align_mask) & ~align_mask;
711 // Check if we have space on the stack.
712 Label stack_limit_hit;
715 ExternalReference stack_limit =
716 ExternalReference::address_of_stack_limit(isolate());
717 __ Mov(x10, stack_limit);
718 __ Ldr(x10, MemOperand(x10));
719 __ Subs(x10, csp, x10);
721 // Handle it if the stack pointer is already below the stack limit.
722 __ B(ls, &stack_limit_hit);
724 // Check if there is room for the variable number of registers above
726 __ Cmp(x10, num_wreg_to_allocate * kWRegSize);
729 // Exit with OutOfMemory exception. There is not enough space on the stack
730 // for our working registers.
731 __ Mov(w0, EXCEPTION);
734 __ Bind(&stack_limit_hit);
735 CallCheckStackGuardState(x10);
736 // If returned value is non-zero, we exit with the returned value as result.
737 __ Cbnz(w0, &return_w0);
741 // Allocate space on stack.
742 __ Claim(num_wreg_to_allocate, kWRegSize);
744 // Initialize success_counter with 0.
745 __ Str(wzr, MemOperand(frame_pointer(), kSuccessCounter));
747 // Find negative length (offset of start relative to end).
748 __ Sub(x10, input_start(), input_end());
749 if (masm_->emit_debug_code()) {
750 // Check that the input string length is < 2^30.
752 __ Cmp(x11, (1<<30) - 1);
753 __ Check(ls, kInputStringTooLong);
755 __ Mov(current_input_offset(), w10);
757 // The non-position value is used as a clearing value for the
758 // capture registers, it corresponds to the position of the first character
760 __ Sub(non_position_value(), current_input_offset(), char_size());
761 __ Sub(non_position_value(), non_position_value(),
762 Operand(start_offset(), LSL, (mode_ == UC16) ? 1 : 0));
763 // We can store this value twice in an X register for initializing
764 // on-stack registers later.
765 __ Orr(twice_non_position_value(),
766 non_position_value().X(),
767 Operand(non_position_value().X(), LSL, kWRegSizeInBits));
769 // Initialize code pointer register.
770 __ Mov(code_pointer(), Operand(masm_->CodeObject()));
772 Label load_char_start_regexp, start_regexp;
773 // Load newline if index is at start, previous character otherwise.
774 __ Cbnz(start_offset(), &load_char_start_regexp);
775 __ Mov(current_character(), '\n');
778 // Global regexp restarts matching here.
779 __ Bind(&load_char_start_regexp);
780 // Load previous char as initial value of current character register.
781 LoadCurrentCharacterUnchecked(-1, 1);
782 __ Bind(&start_regexp);
783 // Initialize on-stack registers.
784 if (num_saved_registers_ > 0) {
785 ClearRegisters(0, num_saved_registers_ - 1);
788 // Initialize backtrack stack pointer.
789 __ Ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackBase));
794 if (backtrack_label_.is_linked()) {
795 __ Bind(&backtrack_label_);
799 if (success_label_.is_linked()) {
800 Register first_capture_start = w15;
802 // Save captures when successful.
803 __ Bind(&success_label_);
805 if (num_saved_registers_ > 0) {
806 // V8 expects the output to be an int32_t array.
807 Register capture_start = w12;
808 Register capture_end = w13;
809 Register input_length = w14;
811 // Copy captures to output.
813 // Get string length.
814 __ Sub(x10, input_end(), input_start());
815 if (masm_->emit_debug_code()) {
816 // Check that the input string length is < 2^30.
817 __ Cmp(x10, (1<<30) - 1);
818 __ Check(ls, kInputStringTooLong);
820 // input_start has a start_offset offset on entry. We need to include
821 // it when computing the length of the whole string.
823 __ Add(input_length, start_offset(), Operand(w10, LSR, 1));
825 __ Add(input_length, start_offset(), w10);
828 // Copy the results to the output array from the cached registers first.
830 (i < num_saved_registers_) && (i < kNumCachedRegisters);
832 __ Mov(capture_start.X(), GetCachedRegister(i));
833 __ Lsr(capture_end.X(), capture_start.X(), kWRegSizeInBits);
834 if ((i == 0) && global_with_zero_length_check()) {
835 // Keep capture start for the zero-length check later.
836 __ Mov(first_capture_start, capture_start);
838 // Offsets need to be relative to the start of the string.
840 __ Add(capture_start, input_length, Operand(capture_start, ASR, 1));
841 __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
843 __ Add(capture_start, input_length, capture_start);
844 __ Add(capture_end, input_length, capture_end);
846 // The output pointer advances for a possible global match.
847 __ Stp(capture_start,
849 MemOperand(output_array(), kPointerSize, PostIndex));
852 // Only carry on if there are more than kNumCachedRegisters capture
854 int num_registers_left_on_stack =
855 num_saved_registers_ - kNumCachedRegisters;
856 if (num_registers_left_on_stack > 0) {
858 // There are always an even number of capture registers. A couple of
859 // registers determine one match with two offsets.
860 ASSERT_EQ(0, num_registers_left_on_stack % 2);
861 __ Add(base, frame_pointer(), kFirstCaptureOnStack);
863 // We can unroll the loop here, we should not unroll for less than 2
865 STATIC_ASSERT(kNumRegistersToUnroll > 2);
866 if (num_registers_left_on_stack <= kNumRegistersToUnroll) {
867 for (int i = 0; i < num_registers_left_on_stack / 2; i++) {
870 MemOperand(base, -kPointerSize, PostIndex));
871 if ((i == 0) && global_with_zero_length_check()) {
872 // Keep capture start for the zero-length check later.
873 __ Mov(first_capture_start, capture_start);
875 // Offsets need to be relative to the start of the string.
877 __ Add(capture_start,
879 Operand(capture_start, ASR, 1));
880 __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
882 __ Add(capture_start, input_length, capture_start);
883 __ Add(capture_end, input_length, capture_end);
885 // The output pointer advances for a possible global match.
886 __ Stp(capture_start,
888 MemOperand(output_array(), kPointerSize, PostIndex));
892 __ Mov(x11, num_registers_left_on_stack);
896 MemOperand(base, -kPointerSize, PostIndex));
897 if (global_with_zero_length_check()) {
898 __ Mov(first_capture_start, capture_start);
905 MemOperand(base, -kPointerSize, PostIndex));
908 __ Add(capture_start, input_length, Operand(capture_start, ASR, 1));
909 __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
911 __ Add(capture_start, input_length, capture_start);
912 __ Add(capture_end, input_length, capture_end);
914 // The output pointer advances for a possible global match.
915 __ Stp(capture_start,
917 MemOperand(output_array(), kPointerSize, PostIndex));
925 Register success_counter = w0;
926 Register output_size = x10;
927 // Restart matching if the regular expression is flagged as global.
929 // Increment success counter.
930 __ Ldr(success_counter, MemOperand(frame_pointer(), kSuccessCounter));
931 __ Add(success_counter, success_counter, 1);
932 __ Str(success_counter, MemOperand(frame_pointer(), kSuccessCounter));
934 // Capture results have been stored, so the number of remaining global
935 // output registers is reduced by the number of stored captures.
936 __ Ldr(output_size, MemOperand(frame_pointer(), kOutputSize));
937 __ Sub(output_size, output_size, num_saved_registers_);
938 // Check whether we have enough room for another set of capture results.
939 __ Cmp(output_size, num_saved_registers_);
940 __ B(lt, &return_w0);
942 // The output pointer is already set to the next field in the output
944 // Update output size on the frame before we restart matching.
945 __ Str(output_size, MemOperand(frame_pointer(), kOutputSize));
947 if (global_with_zero_length_check()) {
948 // Special case for zero-length matches.
949 __ Cmp(current_input_offset(), first_capture_start);
950 // Not a zero-length match, restart.
951 __ B(ne, &load_char_start_regexp);
952 // Offset from the end is zero if we already reached the end.
953 __ Cbz(current_input_offset(), &return_w0);
954 // Advance current position after a zero-length match.
955 __ Add(current_input_offset(),
956 current_input_offset(),
957 Operand((mode_ == UC16) ? 2 : 1));
960 __ B(&load_char_start_regexp);
966 if (exit_label_.is_linked()) {
967 // Exit and return w0
968 __ Bind(&exit_label_);
970 __ Ldr(w0, MemOperand(frame_pointer(), kSuccessCounter));
976 // Set stack pointer back to first register to retain
977 ASSERT(csp.Is(__ StackPointer()));
980 // Restore registers.
981 __ PopCPURegList(registers_to_retain);
985 Label exit_with_exception;
986 // Registers x0 to x7 are used to store the first captures, they need to be
987 // retained over calls to C++ code.
988 CPURegList cached_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 7);
989 ASSERT((cached_registers.Count() * 2) == kNumCachedRegisters);
991 if (check_preempt_label_.is_linked()) {
992 __ Bind(&check_preempt_label_);
994 // The cached registers need to be retained.
995 __ PushCPURegList(cached_registers);
996 CallCheckStackGuardState(x10);
997 // Returning from the regexp code restores the stack (csp <- fp)
998 // so we don't need to drop the link register from it before exiting.
999 __ Cbnz(w0, &return_w0);
1000 // Reset the cached registers.
1001 __ PopCPURegList(cached_registers);
1002 RestoreLinkRegister();
1006 if (stack_overflow_label_.is_linked()) {
1007 __ Bind(&stack_overflow_label_);
1009 // The cached registers need to be retained.
1010 __ PushCPURegList(cached_registers);
1011 // Call GrowStack(backtrack_stackpointer(), &stack_base)
1012 __ Mov(x2, ExternalReference::isolate_address(isolate()));
1013 __ Add(x1, frame_pointer(), kStackBase);
1014 __ Mov(x0, backtrack_stackpointer());
1015 ExternalReference grow_stack =
1016 ExternalReference::re_grow_stack(isolate());
1017 __ CallCFunction(grow_stack, 3);
1018 // If return NULL, we have failed to grow the stack, and
1019 // must exit with a stack-overflow exception.
1020 // Returning from the regexp code restores the stack (csp <- fp)
1021 // so we don't need to drop the link register from it before exiting.
1022 __ Cbz(w0, &exit_with_exception);
1023 // Otherwise use return value as new stack pointer.
1024 __ Mov(backtrack_stackpointer(), x0);
1025 // Reset the cached registers.
1026 __ PopCPURegList(cached_registers);
1027 RestoreLinkRegister();
1031 if (exit_with_exception.is_linked()) {
1032 __ Bind(&exit_with_exception);
1033 __ Mov(w0, EXCEPTION);
1038 masm_->GetCode(&code_desc);
1039 Handle<Code> code = isolate()->factory()->NewCode(
1040 code_desc, Code::ComputeFlags(Code::REGEXP), masm_->CodeObject());
1041 PROFILE(masm_->isolate(), RegExpCodeCreateEvent(*code, *source));
1042 return Handle<HeapObject>::cast(code);
1046 void RegExpMacroAssemblerARM64::GoTo(Label* to) {
1047 BranchOrBacktrack(al, to);
1050 void RegExpMacroAssemblerARM64::IfRegisterGE(int reg, int comparand,
1052 Register to_compare = GetRegister(reg, w10);
1053 CompareAndBranchOrBacktrack(to_compare, comparand, ge, if_ge);
1057 void RegExpMacroAssemblerARM64::IfRegisterLT(int reg, int comparand,
1059 Register to_compare = GetRegister(reg, w10);
1060 CompareAndBranchOrBacktrack(to_compare, comparand, lt, if_lt);
1064 void RegExpMacroAssemblerARM64::IfRegisterEqPos(int reg, Label* if_eq) {
1065 Register to_compare = GetRegister(reg, w10);
1066 __ Cmp(to_compare, current_input_offset());
1067 BranchOrBacktrack(eq, if_eq);
1070 RegExpMacroAssembler::IrregexpImplementation
1071 RegExpMacroAssemblerARM64::Implementation() {
1072 return kARM64Implementation;
1076 void RegExpMacroAssemblerARM64::LoadCurrentCharacter(int cp_offset,
1077 Label* on_end_of_input,
1080 // TODO(pielan): Make sure long strings are caught before this, and not
1081 // just asserted in debug mode.
1082 ASSERT(cp_offset >= -1); // ^ and \b can look behind one character.
1083 // Be sane! (And ensure that an int32_t can be used to index the string)
1084 ASSERT(cp_offset < (1<<30));
1086 CheckPosition(cp_offset + characters - 1, on_end_of_input);
1088 LoadCurrentCharacterUnchecked(cp_offset, characters);
1092 void RegExpMacroAssemblerARM64::PopCurrentPosition() {
1093 Pop(current_input_offset());
1097 void RegExpMacroAssemblerARM64::PopRegister(int register_index) {
1099 StoreRegister(register_index, w10);
1103 void RegExpMacroAssemblerARM64::PushBacktrack(Label* label) {
1104 if (label->is_bound()) {
1105 int target = label->pos();
1106 __ Mov(w10, target + Code::kHeaderSize - kHeapObjectTag);
1108 __ Adr(x10, label, MacroAssembler::kAdrFar);
1109 __ Sub(x10, x10, code_pointer());
1110 if (masm_->emit_debug_code()) {
1111 __ Cmp(x10, kWRegMask);
1112 // The code offset has to fit in a W register.
1113 __ Check(ls, kOffsetOutOfRange);
1121 void RegExpMacroAssemblerARM64::PushCurrentPosition() {
1122 Push(current_input_offset());
1126 void RegExpMacroAssemblerARM64::PushRegister(int register_index,
1127 StackCheckFlag check_stack_limit) {
1128 Register to_push = GetRegister(register_index, w10);
1130 if (check_stack_limit) CheckStackLimit();
1134 void RegExpMacroAssemblerARM64::ReadCurrentPositionFromRegister(int reg) {
1135 Register cached_register;
1136 RegisterState register_state = GetRegisterState(reg);
1137 switch (register_state) {
1139 __ Ldr(current_input_offset(), register_location(reg));
1142 cached_register = GetCachedRegister(reg);
1143 __ Mov(current_input_offset(), cached_register.W());
1146 cached_register = GetCachedRegister(reg);
1147 __ Lsr(current_input_offset().X(), cached_register, kWRegSizeInBits);
1156 void RegExpMacroAssemblerARM64::ReadStackPointerFromRegister(int reg) {
1157 Register read_from = GetRegister(reg, w10);
1158 __ Ldr(x11, MemOperand(frame_pointer(), kStackBase));
1159 __ Add(backtrack_stackpointer(), x11, Operand(read_from, SXTW));
1163 void RegExpMacroAssemblerARM64::SetCurrentPositionFromEnd(int by) {
1164 Label after_position;
1165 __ Cmp(current_input_offset(), -by * char_size());
1166 __ B(ge, &after_position);
1167 __ Mov(current_input_offset(), -by * char_size());
1168 // On RegExp code entry (where this operation is used), the character before
1169 // the current position is expected to be already loaded.
1170 // We have advanced the position, so it's safe to read backwards.
1171 LoadCurrentCharacterUnchecked(-1, 1);
1172 __ Bind(&after_position);
1176 void RegExpMacroAssemblerARM64::SetRegister(int register_index, int to) {
1177 ASSERT(register_index >= num_saved_registers_); // Reserved for positions!
1178 Register set_to = wzr;
1183 StoreRegister(register_index, set_to);
1187 bool RegExpMacroAssemblerARM64::Succeed() {
1188 __ B(&success_label_);
1193 void RegExpMacroAssemblerARM64::WriteCurrentPositionToRegister(int reg,
1195 Register position = current_input_offset();
1196 if (cp_offset != 0) {
1198 __ Add(position, current_input_offset(), cp_offset * char_size());
1200 StoreRegister(reg, position);
1204 void RegExpMacroAssemblerARM64::ClearRegisters(int reg_from, int reg_to) {
1205 ASSERT(reg_from <= reg_to);
1206 int num_registers = reg_to - reg_from + 1;
1208 // If the first capture register is cached in a hardware register but not
1209 // aligned on a 64-bit one, we need to clear the first one specifically.
1210 if ((reg_from < kNumCachedRegisters) && ((reg_from % 2) != 0)) {
1211 StoreRegister(reg_from, non_position_value());
1216 // Clear cached registers in pairs as far as possible.
1217 while ((num_registers >= 2) && (reg_from < kNumCachedRegisters)) {
1218 ASSERT(GetRegisterState(reg_from) == CACHED_LSW);
1219 __ Mov(GetCachedRegister(reg_from), twice_non_position_value());
1224 if ((num_registers % 2) == 1) {
1225 StoreRegister(reg_from, non_position_value());
1230 if (num_registers > 0) {
1231 // If there are some remaining registers, they are stored on the stack.
1232 ASSERT(reg_from >= kNumCachedRegisters);
1234 // Move down the indexes of the registers on stack to get the correct offset
1236 reg_from -= kNumCachedRegisters;
1237 reg_to -= kNumCachedRegisters;
1238 // We should not unroll the loop for less than 2 registers.
1239 STATIC_ASSERT(kNumRegistersToUnroll > 2);
1240 // We position the base pointer to (reg_from + 1).
1241 int base_offset = kFirstRegisterOnStack -
1242 kWRegSize - (kWRegSize * reg_from);
1243 if (num_registers > kNumRegistersToUnroll) {
1244 Register base = x10;
1245 __ Add(base, frame_pointer(), base_offset);
1248 __ Mov(x11, num_registers);
1250 __ Str(twice_non_position_value(),
1251 MemOperand(base, -kPointerSize, PostIndex));
1252 __ Sub(x11, x11, 2);
1253 __ Cbnz(x11, &loop);
1255 for (int i = reg_from; i <= reg_to; i += 2) {
1256 __ Str(twice_non_position_value(),
1257 MemOperand(frame_pointer(), base_offset));
1258 base_offset -= kWRegSize * 2;
1265 void RegExpMacroAssemblerARM64::WriteStackPointerToRegister(int reg) {
1266 __ Ldr(x10, MemOperand(frame_pointer(), kStackBase));
1267 __ Sub(x10, backtrack_stackpointer(), x10);
1268 if (masm_->emit_debug_code()) {
1269 __ Cmp(x10, Operand(w10, SXTW));
1270 // The stack offset needs to fit in a W register.
1271 __ Check(eq, kOffsetOutOfRange);
1273 StoreRegister(reg, w10);
1277 // Helper function for reading a value out of a stack frame.
1278 template <typename T>
1279 static T& frame_entry(Address re_frame, int frame_offset) {
1280 return *reinterpret_cast<T*>(re_frame + frame_offset);
1284 int RegExpMacroAssemblerARM64::CheckStackGuardState(Address* return_address,
1288 const byte** input_start,
1289 const byte** input_end) {
1290 Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
1291 if (isolate->stack_guard()->IsStackOverflow()) {
1292 isolate->StackOverflow();
1296 // If not real stack overflow the stack guard was used to interrupt
1297 // execution for another purpose.
1299 // If this is a direct call from JavaScript retry the RegExp forcing the call
1300 // through the runtime system. Currently the direct call cannot handle a GC.
1301 if (frame_entry<int>(re_frame, kDirectCall) == 1) {
1305 // Prepare for possible GC.
1306 HandleScope handles(isolate);
1307 Handle<Code> code_handle(re_code);
1309 Handle<String> subject(frame_entry<String*>(re_frame, kInput));
1312 bool is_ascii = subject->IsOneByteRepresentationUnderneath();
1314 ASSERT(re_code->instruction_start() <= *return_address);
1315 ASSERT(*return_address <=
1316 re_code->instruction_start() + re_code->instruction_size());
1318 Object* result = Execution::HandleStackGuardInterrupt(isolate);
1320 if (*code_handle != re_code) { // Return address no longer valid
1321 int delta = code_handle->address() - re_code->address();
1322 // Overwrite the return address on the stack.
1323 *return_address += delta;
1326 if (result->IsException()) {
1330 Handle<String> subject_tmp = subject;
1331 int slice_offset = 0;
1333 // Extract the underlying string and the slice offset.
1334 if (StringShape(*subject_tmp).IsCons()) {
1335 subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
1336 } else if (StringShape(*subject_tmp).IsSliced()) {
1337 SlicedString* slice = SlicedString::cast(*subject_tmp);
1338 subject_tmp = Handle<String>(slice->parent());
1339 slice_offset = slice->offset();
1342 // String might have changed.
1343 if (subject_tmp->IsOneByteRepresentation() != is_ascii) {
1344 // If we changed between an ASCII and an UC16 string, the specialized
1345 // code cannot be used, and we need to restart regexp matching from
1346 // scratch (including, potentially, compiling a new version of the code).
1350 // Otherwise, the content of the string might have moved. It must still
1351 // be a sequential or external string with the same content.
1352 // Update the start and end pointers in the stack frame to the current
1353 // location (whether it has actually moved or not).
1354 ASSERT(StringShape(*subject_tmp).IsSequential() ||
1355 StringShape(*subject_tmp).IsExternal());
1357 // The original start address of the characters to match.
1358 const byte* start_address = *input_start;
1360 // Find the current start address of the same character at the current string
1362 const byte* new_address = StringCharacterPosition(*subject_tmp,
1363 start_offset + slice_offset);
1365 if (start_address != new_address) {
1366 // If there is a difference, update the object pointer and start and end
1367 // addresses in the RegExp stack frame to match the new value.
1368 const byte* end_address = *input_end;
1369 int byte_length = static_cast<int>(end_address - start_address);
1370 frame_entry<const String*>(re_frame, kInput) = *subject;
1371 *input_start = new_address;
1372 *input_end = new_address + byte_length;
1373 } else if (frame_entry<const String*>(re_frame, kInput) != *subject) {
1374 // Subject string might have been a ConsString that underwent
1375 // short-circuiting during GC. That will not change start_address but
1376 // will change pointer inside the subject handle.
1377 frame_entry<const String*>(re_frame, kInput) = *subject;
1384 void RegExpMacroAssemblerARM64::CheckPosition(int cp_offset,
1385 Label* on_outside_input) {
1386 CompareAndBranchOrBacktrack(current_input_offset(),
1387 -cp_offset * char_size(),
1393 bool RegExpMacroAssemblerARM64::CanReadUnaligned() {
1394 // TODO(pielan): See whether or not we should disable unaligned accesses.
1395 return !slow_safe();
1401 void RegExpMacroAssemblerARM64::CallCheckStackGuardState(Register scratch) {
1402 // Allocate space on the stack to store the return address. The
1403 // CheckStackGuardState C++ function will override it if the code
1404 // moved. Allocate extra space for 2 arguments passed by pointers.
1405 // AAPCS64 requires the stack to be 16 byte aligned.
1406 int alignment = masm_->ActivationFrameAlignment();
1407 ASSERT_EQ(alignment % 16, 0);
1408 int align_mask = (alignment / kXRegSize) - 1;
1409 int xreg_to_claim = (3 + align_mask) & ~align_mask;
1411 ASSERT(csp.Is(__ StackPointer()));
1412 __ Claim(xreg_to_claim);
1414 // CheckStackGuardState needs the end and start addresses of the input string.
1415 __ Poke(input_end(), 2 * kPointerSize);
1416 __ Add(x5, csp, 2 * kPointerSize);
1417 __ Poke(input_start(), kPointerSize);
1418 __ Add(x4, csp, kPointerSize);
1420 __ Mov(w3, start_offset());
1421 // RegExp code frame pointer.
1422 __ Mov(x2, frame_pointer());
1424 __ Mov(x1, Operand(masm_->CodeObject()));
1426 // We need to pass a pointer to the return address as first argument.
1427 // The DirectCEntry stub will place the return address on the stack before
1428 // calling so the stack pointer will point to it.
1431 ExternalReference check_stack_guard_state =
1432 ExternalReference::re_check_stack_guard_state(isolate());
1433 __ Mov(scratch, check_stack_guard_state);
1434 DirectCEntryStub stub(isolate());
1435 stub.GenerateCall(masm_, scratch);
1437 // The input string may have been moved in memory, we need to reload it.
1438 __ Peek(input_start(), kPointerSize);
1439 __ Peek(input_end(), 2 * kPointerSize);
1441 ASSERT(csp.Is(__ StackPointer()));
1442 __ Drop(xreg_to_claim);
1444 // Reload the Code pointer.
1445 __ Mov(code_pointer(), Operand(masm_->CodeObject()));
1448 void RegExpMacroAssemblerARM64::BranchOrBacktrack(Condition condition,
1450 if (condition == al) { // Unconditional.
1459 to = &backtrack_label_;
1461 // TODO(ulan): do direct jump when jump distance is known and fits in imm19.
1462 Condition inverted_condition = InvertCondition(condition);
1464 __ B(inverted_condition, &no_branch);
1466 __ Bind(&no_branch);
1469 void RegExpMacroAssemblerARM64::CompareAndBranchOrBacktrack(Register reg,
1471 Condition condition,
1473 if ((immediate == 0) && ((condition == eq) || (condition == ne))) {
1475 to = &backtrack_label_;
1477 // TODO(ulan): do direct jump when jump distance is known and fits in imm19.
1479 if (condition == eq) {
1480 __ Cbnz(reg, &no_branch);
1482 __ Cbz(reg, &no_branch);
1485 __ Bind(&no_branch);
1487 __ Cmp(reg, immediate);
1488 BranchOrBacktrack(condition, to);
1493 void RegExpMacroAssemblerARM64::CheckPreemption() {
1494 // Check for preemption.
1495 ExternalReference stack_limit =
1496 ExternalReference::address_of_stack_limit(isolate());
1497 __ Mov(x10, stack_limit);
1498 __ Ldr(x10, MemOperand(x10));
1499 ASSERT(csp.Is(__ StackPointer()));
1501 CallIf(&check_preempt_label_, ls);
1505 void RegExpMacroAssemblerARM64::CheckStackLimit() {
1506 ExternalReference stack_limit =
1507 ExternalReference::address_of_regexp_stack_limit(isolate());
1508 __ Mov(x10, stack_limit);
1509 __ Ldr(x10, MemOperand(x10));
1510 __ Cmp(backtrack_stackpointer(), x10);
1511 CallIf(&stack_overflow_label_, ls);
1515 void RegExpMacroAssemblerARM64::Push(Register source) {
1516 ASSERT(source.Is32Bits());
1517 ASSERT(!source.is(backtrack_stackpointer()));
1519 MemOperand(backtrack_stackpointer(),
1520 -static_cast<int>(kWRegSize),
1525 void RegExpMacroAssemblerARM64::Pop(Register target) {
1526 ASSERT(target.Is32Bits());
1527 ASSERT(!target.is(backtrack_stackpointer()));
1529 MemOperand(backtrack_stackpointer(), kWRegSize, PostIndex));
1533 Register RegExpMacroAssemblerARM64::GetCachedRegister(int register_index) {
1534 ASSERT(register_index < kNumCachedRegisters);
1535 return Register::Create(register_index / 2, kXRegSizeInBits);
1539 Register RegExpMacroAssemblerARM64::GetRegister(int register_index,
1540 Register maybe_result) {
1541 ASSERT(maybe_result.Is32Bits());
1542 ASSERT(register_index >= 0);
1543 if (num_registers_ <= register_index) {
1544 num_registers_ = register_index + 1;
1547 RegisterState register_state = GetRegisterState(register_index);
1548 switch (register_state) {
1550 __ Ldr(maybe_result, register_location(register_index));
1551 result = maybe_result;
1554 result = GetCachedRegister(register_index).W();
1557 __ Lsr(maybe_result.X(), GetCachedRegister(register_index),
1559 result = maybe_result;
1565 ASSERT(result.Is32Bits());
1570 void RegExpMacroAssemblerARM64::StoreRegister(int register_index,
1572 ASSERT(source.Is32Bits());
1573 ASSERT(register_index >= 0);
1574 if (num_registers_ <= register_index) {
1575 num_registers_ = register_index + 1;
1578 Register cached_register;
1579 RegisterState register_state = GetRegisterState(register_index);
1580 switch (register_state) {
1582 __ Str(source, register_location(register_index));
1585 cached_register = GetCachedRegister(register_index);
1586 if (!source.Is(cached_register.W())) {
1587 __ Bfi(cached_register, source.X(), 0, kWRegSizeInBits);
1591 cached_register = GetCachedRegister(register_index);
1592 __ Bfi(cached_register, source.X(), kWRegSizeInBits, kWRegSizeInBits);
1601 void RegExpMacroAssemblerARM64::CallIf(Label* to, Condition condition) {
1603 if (condition != al) __ B(&skip_call, InvertCondition(condition));
1605 __ Bind(&skip_call);
1609 void RegExpMacroAssemblerARM64::RestoreLinkRegister() {
1610 ASSERT(csp.Is(__ StackPointer()));
1612 __ Add(lr, lr, Operand(masm_->CodeObject()));
1616 void RegExpMacroAssemblerARM64::SaveLinkRegister() {
1617 ASSERT(csp.Is(__ StackPointer()));
1618 __ Sub(lr, lr, Operand(masm_->CodeObject()));
1623 MemOperand RegExpMacroAssemblerARM64::register_location(int register_index) {
1624 ASSERT(register_index < (1<<30));
1625 ASSERT(register_index >= kNumCachedRegisters);
1626 if (num_registers_ <= register_index) {
1627 num_registers_ = register_index + 1;
1629 register_index -= kNumCachedRegisters;
1630 int offset = kFirstRegisterOnStack - register_index * kWRegSize;
1631 return MemOperand(frame_pointer(), offset);
1634 MemOperand RegExpMacroAssemblerARM64::capture_location(int register_index,
1636 ASSERT(register_index < (1<<30));
1637 ASSERT(register_index < num_saved_registers_);
1638 ASSERT(register_index >= kNumCachedRegisters);
1639 ASSERT_EQ(register_index % 2, 0);
1640 register_index -= kNumCachedRegisters;
1641 int offset = kFirstCaptureOnStack - register_index * kWRegSize;
1642 // capture_location is used with Stp instructions to load/store 2 registers.
1643 // The immediate field in the encoding is limited to 7 bits (signed).
1644 if (is_int7(offset)) {
1645 return MemOperand(frame_pointer(), offset);
1647 __ Add(scratch, frame_pointer(), offset);
1648 return MemOperand(scratch);
1652 void RegExpMacroAssemblerARM64::LoadCurrentCharacterUnchecked(int cp_offset,
1654 Register offset = current_input_offset();
1656 // The ldr, str, ldrh, strh instructions can do unaligned accesses, if the CPU
1657 // and the operating system running on the target allow it.
1658 // If unaligned load/stores are not supported then this function must only
1659 // be used to load a single character at a time.
1661 // ARMv8 supports unaligned accesses but V8 or the kernel can decide to
1663 // TODO(pielan): See whether or not we should disable unaligned accesses.
1664 if (!CanReadUnaligned()) {
1665 ASSERT(characters == 1);
1668 if (cp_offset != 0) {
1669 if (masm_->emit_debug_code()) {
1670 __ Mov(x10, cp_offset * char_size());
1671 __ Add(x10, x10, Operand(current_input_offset(), SXTW));
1672 __ Cmp(x10, Operand(w10, SXTW));
1673 // The offset needs to fit in a W register.
1674 __ Check(eq, kOffsetOutOfRange);
1676 __ Add(w10, current_input_offset(), cp_offset * char_size());
1681 if (mode_ == ASCII) {
1682 if (characters == 4) {
1683 __ Ldr(current_character(), MemOperand(input_end(), offset, SXTW));
1684 } else if (characters == 2) {
1685 __ Ldrh(current_character(), MemOperand(input_end(), offset, SXTW));
1687 ASSERT(characters == 1);
1688 __ Ldrb(current_character(), MemOperand(input_end(), offset, SXTW));
1691 ASSERT(mode_ == UC16);
1692 if (characters == 2) {
1693 __ Ldr(current_character(), MemOperand(input_end(), offset, SXTW));
1695 ASSERT(characters == 1);
1696 __ Ldrh(current_character(), MemOperand(input_end(), offset, SXTW));
1701 #endif // V8_INTERPRETED_REGEXP
1703 }} // namespace v8::internal
1705 #endif // V8_TARGET_ARCH_ARM64