Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / v8 / src / arm64 / regexp-macro-assembler-arm64.cc
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.
4
5 #include "v8.h"
6
7 #if V8_TARGET_ARCH_ARM64
8
9 #include "cpu-profiler.h"
10 #include "unicode.h"
11 #include "log.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"
17
18 namespace v8 {
19 namespace internal {
20
21 #ifndef V8_INTERPRETED_REGEXP
22 /*
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
42  *             RegExp registers.
43  * - x16/x17 : IP registers, used by assembler. Very volatile.
44  * - csp     : Points to tip of C stack.
45  *
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
48  *             is done.
49  *
50  * The remaining registers are free for computations.
51  * Each call to a public method should retain this convention.
52  *
53  * The stack will have the following structure:
54  *
55  *  Location    Name               Description
56  *              (as referred to in
57  *              the code)
58  *
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
62  *                                 native call.
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.
81  *  -           ...
82  *  -           register N + num_registers - 1
83  *  ^^^^^^^^^ csp ^^^^^^^^^
84  *
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.
88  *
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,
93  *              int start_offset,
94  *              Address input_start,
95  *              Address input_end,
96  *              int* output,
97  *              int output_size,
98  *              Address stack_base,
99  *              bool direct_call = false,
100  *              Address secondary_return_address,  // Only used by native call.
101  *              Isolate* isolate)
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.
109  */
110
111 #define __ ACCESS_MASM(masm_)
112
113 RegExpMacroAssemblerARM64::RegExpMacroAssemblerARM64(
114     Mode mode,
115     int registers_to_save,
116     Zone* zone)
117     : NativeRegExpMacroAssembler(zone),
118       masm_(new MacroAssembler(zone->isolate(), NULL, kRegExpCodeSize)),
119       mode_(mode),
120       num_registers_(registers_to_save),
121       num_saved_registers_(registers_to_save),
122       entry_label_(),
123       start_label_(),
124       success_label_(),
125       backtrack_label_(),
126       exit_label_() {
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.
134 }
135
136
137 RegExpMacroAssemblerARM64::~RegExpMacroAssemblerARM64() {
138   delete masm_;
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();
144   exit_label_.Unuse();
145   check_preempt_label_.Unuse();
146   stack_overflow_label_.Unuse();
147 }
148
149 int RegExpMacroAssemblerARM64::stack_limit_slack()  {
150   return RegExpStack::kStackLimitSlack;
151 }
152
153
154 void RegExpMacroAssemblerARM64::AdvanceCurrentPosition(int by) {
155   if (by != 0) {
156     __ Add(current_input_offset(),
157            current_input_offset(), by * char_size());
158   }
159 }
160
161
162 void RegExpMacroAssemblerARM64::AdvanceRegister(int reg, int by) {
163   ASSERT((reg >= 0) && (reg < num_registers_));
164   if (by != 0) {
165     Register to_advance;
166     RegisterState register_state = GetRegisterState(reg);
167     switch (register_state) {
168       case STACKED:
169         __ Ldr(w10, register_location(reg));
170         __ Add(w10, w10, by);
171         __ Str(w10, register_location(reg));
172         break;
173       case CACHED_LSW:
174         to_advance = GetCachedRegister(reg);
175         __ Add(to_advance, to_advance, by);
176         break;
177       case CACHED_MSW:
178         to_advance = GetCachedRegister(reg);
179         __ Add(to_advance, to_advance,
180                static_cast<int64_t>(by) << kWRegSizeInBits);
181         break;
182       default:
183         UNREACHABLE();
184         break;
185     }
186   }
187 }
188
189
190 void RegExpMacroAssemblerARM64::Backtrack() {
191   CheckPreemption();
192   Pop(w10);
193   __ Add(x10, code_pointer(), Operand(w10, UXTW));
194   __ Br(x10);
195 }
196
197
198 void RegExpMacroAssemblerARM64::Bind(Label* label) {
199   __ Bind(label);
200 }
201
202
203 void RegExpMacroAssemblerARM64::CheckCharacter(uint32_t c, Label* on_equal) {
204   CompareAndBranchOrBacktrack(current_character(), c, eq, on_equal);
205 }
206
207
208 void RegExpMacroAssemblerARM64::CheckCharacterGT(uc16 limit,
209                                                  Label* on_greater) {
210   CompareAndBranchOrBacktrack(current_character(), limit, hi, on_greater);
211 }
212
213
214 void RegExpMacroAssemblerARM64::CheckAtStart(Label* on_at_start) {
215   Label not_at_start;
216   // Did we start the match at the start of the input string?
217   CompareAndBranchOrBacktrack(start_offset(), 0, ne, &not_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(&not_at_start);
223 }
224
225
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);
233 }
234
235
236 void RegExpMacroAssemblerARM64::CheckCharacterLT(uc16 limit, Label* on_less) {
237   CompareAndBranchOrBacktrack(current_character(), limit, lo, on_less);
238 }
239
240
241 void RegExpMacroAssemblerARM64::CheckCharacters(Vector<const uc16> str,
242                                               int cp_offset,
243                                               Label* on_failure,
244                                               bool check_end_of_string) {
245   // This method is only ever called from the cctests.
246
247   if (check_end_of_string) {
248     // Is last character of required match inside string.
249     CheckPosition(cp_offset + str.length() - 1, on_failure);
250   }
251
252   Register characters_address = x11;
253
254   __ Add(characters_address,
255          input_end(),
256          Operand(current_input_offset(), SXTW));
257   if (cp_offset != 0) {
258     __ Add(characters_address, characters_address, cp_offset * char_size());
259   }
260
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);
265     } else {
266       __ Ldrh(w10, MemOperand(characters_address, 2, PostIndex));
267     }
268     CompareAndBranchOrBacktrack(w10, str[i], ne, on_failure);
269   }
270 }
271
272
273 void RegExpMacroAssemblerARM64::CheckGreedyLoop(Label* on_equal) {
274   __ Ldr(w10, MemOperand(backtrack_stackpointer()));
275   __ Cmp(current_input_offset(), w10);
276   __ Cset(x11, eq);
277   __ Add(backtrack_stackpointer(),
278          backtrack_stackpointer(), Operand(x11, LSL, kWRegSizeLog2));
279   BranchOrBacktrack(eq, on_equal);
280 }
281
282 void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase(
283     int start_reg,
284     Label* on_no_match) {
285   Label fallthrough;
286
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));
292
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);
298   } else {
299     __ Ldp(w11, capture_start_offset, capture_location(start_reg, x10));
300   }
301   __ Sub(capture_length, w11, capture_start_offset);  // Length to check.
302   // Succeed on empty capture (including no capture).
303   __ Cbz(capture_length, &fallthrough);
304
305   // Check that there are enough characters left in the input.
306   __ Cmn(capture_length, current_input_offset());
307   BranchOrBacktrack(gt, on_no_match);
308
309   if (mode_ == ASCII) {
310     Label success;
311     Label fail;
312     Label loop_check;
313
314     Register capture_start_address = x12;
315     Register capture_end_addresss = x13;
316     Register current_position_address = x14;
317
318     __ Add(capture_start_address,
319            input_end(),
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,
325            input_end(),
326            Operand(current_input_offset(), SXTW));
327
328     Label loop;
329     __ Bind(&loop);
330     __ Ldrb(w10, MemOperand(capture_start_address, 1, PostIndex));
331     __ Ldrb(w11, MemOperand(current_position_address, 1, PostIndex));
332     __ Cmp(w10, w11);
333     __ B(eq, &loop_check);
334
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.
338     __ Cmp(w11, w10);
339     __ B(ne, &fail);
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.
348
349     __ Bind(&loop_check);
350     __ Cmp(capture_start_address, capture_end_addresss);
351     __ B(lt, &loop);
352     __ B(&success);
353
354     __ Bind(&fail);
355     BranchOrBacktrack(al, on_no_match);
356
357     __ Bind(&success);
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);
365     }
366   } else {
367     ASSERT(mode_ == UC16);
368     int argument_count = 4;
369
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);
374
375     // Put arguments into arguments registers.
376     // Parameters are
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
381
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));
388     // Isolate.
389     __ Mov(x3, ExternalReference::isolate_address(isolate()));
390
391     {
392       AllowExternalCallThatCantCauseGC scope(masm_);
393       ExternalReference function =
394           ExternalReference::re_case_insensitive_compare_uc16(isolate());
395       __ CallCFunction(function, argument_count);
396     }
397
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);
404   }
405
406   __ Bind(&fallthrough);
407 }
408
409 void RegExpMacroAssemblerARM64::CheckNotBackReference(
410     int start_reg,
411     Label* on_no_match) {
412   Label fallthrough;
413
414   Register capture_start_address = x12;
415   Register capture_end_address = x13;
416   Register current_position_address = x14;
417   Register capture_length = w15;
418
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);
424   } else {
425     __ Ldp(w11, w10, capture_location(start_reg, x10));
426   }
427   __ Sub(capture_length, w11, w10);  // Length to check.
428   // Succeed on empty capture (including no capture).
429   __ Cbz(capture_length, &fallthrough);
430
431   // Check that there are enough characters left in the input.
432   __ Cmn(capture_length, current_input_offset());
433   BranchOrBacktrack(gt, on_no_match);
434
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,
441          input_end(),
442          Operand(current_input_offset(), SXTW));
443
444   Label loop;
445   __ Bind(&loop);
446   if (mode_ == ASCII) {
447     __ Ldrb(w10, MemOperand(capture_start_address, 1, PostIndex));
448     __ Ldrb(w11, MemOperand(current_position_address, 1, PostIndex));
449   } else {
450     ASSERT(mode_ == UC16);
451     __ Ldrh(w10, MemOperand(capture_start_address, 2, PostIndex));
452     __ Ldrh(w11, MemOperand(current_position_address, 2, PostIndex));
453   }
454   __ Cmp(w10, w11);
455   BranchOrBacktrack(ne, on_no_match);
456   __ Cmp(capture_start_address, capture_end_address);
457   __ B(lt, &loop);
458
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);
466   }
467   __ Bind(&fallthrough);
468 }
469
470
471 void RegExpMacroAssemblerARM64::CheckNotCharacter(unsigned c,
472                                                   Label* on_not_equal) {
473   CompareAndBranchOrBacktrack(current_character(), c, ne, on_not_equal);
474 }
475
476
477 void RegExpMacroAssemblerARM64::CheckCharacterAfterAnd(uint32_t c,
478                                                        uint32_t mask,
479                                                        Label* on_equal) {
480   __ And(w10, current_character(), mask);
481   CompareAndBranchOrBacktrack(w10, c, eq, on_equal);
482 }
483
484
485 void RegExpMacroAssemblerARM64::CheckNotCharacterAfterAnd(unsigned c,
486                                                           unsigned mask,
487                                                           Label* on_not_equal) {
488   __ And(w10, current_character(), mask);
489   CompareAndBranchOrBacktrack(w10, c, ne, on_not_equal);
490 }
491
492
493 void RegExpMacroAssemblerARM64::CheckNotCharacterAfterMinusAnd(
494     uc16 c,
495     uc16 minus,
496     uc16 mask,
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);
502 }
503
504
505 void RegExpMacroAssemblerARM64::CheckCharacterInRange(
506     uc16 from,
507     uc16 to,
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);
512 }
513
514
515 void RegExpMacroAssemblerARM64::CheckCharacterNotInRange(
516     uc16 from,
517     uc16 to,
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);
522 }
523
524
525 void RegExpMacroAssemblerARM64::CheckBitInTable(
526     Handle<ByteArray> table,
527     Label* on_bit_set) {
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);
532   } else {
533     __ Add(w10, current_character(), ByteArray::kHeaderSize - kHeapObjectTag);
534   }
535   __ Ldrb(w11, MemOperand(x11, w10, UXTW));
536   CompareAndBranchOrBacktrack(w11, 0, ne, on_bit_set);
537 }
538
539
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
544   switch (type) {
545   case 's':
546     // Match space-characters
547     if (mode_ == ASCII) {
548       // One byte space characters are '\t'..'\r', ' ' and \u00a0.
549       Label success;
550       // Check for ' ' or 0x00a0.
551       __ Cmp(current_character(), ' ');
552       __ Ccmp(current_character(), 0x00a0, ZFlag, ne);
553       __ B(eq, &success);
554       // Check range 0x09..0x0d.
555       __ Sub(w10, current_character(), '\t');
556       CompareAndBranchOrBacktrack(w10, '\r' - '\t', hi, on_no_match);
557       __ Bind(&success);
558       return true;
559     }
560     return false;
561   case 'S':
562     // The emitted code for generic character classes is good enough.
563     return false;
564   case 'd':
565     // Match ASCII digits ('0'..'9').
566     __ Sub(w10, current_character(), '0');
567     CompareAndBranchOrBacktrack(w10, '9' - '0', hi, on_no_match);
568     return true;
569   case 'D':
570     // Match ASCII non-digits.
571     __ Sub(w10, current_character(), '0');
572     CompareAndBranchOrBacktrack(w10, '9' - '0', ls, on_no_match);
573     return true;
574   case '.': {
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);
581     if (mode_ == UC16) {
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);
587     } else {
588       BranchOrBacktrack(eq, on_no_match);
589     }
590     return true;
591   }
592   case 'n': {
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);
598     if (mode_ == UC16) {
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);
604     } else {
605       BranchOrBacktrack(ne, on_no_match);
606     }
607     return true;
608   }
609   case 'w': {
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);
613     }
614     ExternalReference map = ExternalReference::re_word_character_map();
615     __ Mov(x10, map);
616     __ Ldrb(w10, MemOperand(x10, current_character(), UXTW));
617     CompareAndBranchOrBacktrack(w10, 0, eq, on_no_match);
618     return true;
619   }
620   case 'W': {
621     Label done;
622     if (mode_ != ASCII) {
623       // Table is 128 entries, so all ASCII characters can be tested.
624       __ Cmp(current_character(), 'z');
625       __ B(hi, &done);
626     }
627     ExternalReference map = ExternalReference::re_word_character_map();
628     __ Mov(x10, map);
629     __ Ldrb(w10, MemOperand(x10, current_character(), UXTW));
630     CompareAndBranchOrBacktrack(w10, 0, ne, on_no_match);
631     __ Bind(&done);
632     return true;
633   }
634   case '*':
635     // Match any character.
636     return true;
637   // No custom implementation (yet): s(UC16), S(UC16).
638   default:
639     return false;
640   }
641 }
642
643
644 void RegExpMacroAssemblerARM64::Fail() {
645   __ Mov(w0, FAILURE);
646   __ B(&exit_label_);
647 }
648
649
650 Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
651   Label return_w0;
652   // Finalize code - write the entry point code now we know how many
653   // registers we need.
654
655   // Entry code:
656   __ Bind(&entry_label_);
657
658   // Arguments on entry:
659   // x0:  String*  input
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
667
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
671
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);
675
676   // Push registers on the stack, only push the argument registers that we need.
677   CPURegList argument_registers(x0, x5, x6, x7);
678
679   CPURegList registers_to_retain = kCalleeSaved;
680   ASSERT(kCalleeSaved.Count() == 11);
681   registers_to_retain.Combine(lr);
682
683   ASSERT(csp.Is(__ StackPointer()));
684   __ PushCPURegList(registers_to_retain);
685   __ PushCPURegList(argument_registers);
686
687   // Set frame pointer in place.
688   __ Add(frame_pointer(), csp, argument_registers.Count() * kPointerSize);
689
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);
695
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;
704
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;
710
711   // Check if we have space on the stack.
712   Label stack_limit_hit;
713   Label stack_ok;
714
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);
720
721   // Handle it if the stack pointer is already below the stack limit.
722   __ B(ls, &stack_limit_hit);
723
724   // Check if there is room for the variable number of registers above
725   // the stack limit.
726   __ Cmp(x10, num_wreg_to_allocate * kWRegSize);
727   __ B(hs, &stack_ok);
728
729   // Exit with OutOfMemory exception. There is not enough space on the stack
730   // for our working registers.
731   __ Mov(w0, EXCEPTION);
732   __ B(&return_w0);
733
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);
738
739   __ Bind(&stack_ok);
740
741   // Allocate space on stack.
742   __ Claim(num_wreg_to_allocate, kWRegSize);
743
744   // Initialize success_counter with 0.
745   __ Str(wzr, MemOperand(frame_pointer(), kSuccessCounter));
746
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.
751     __ Neg(x11, x10);
752     __ Cmp(x11, (1<<30) - 1);
753     __ Check(ls, kInputStringTooLong);
754   }
755   __ Mov(current_input_offset(), w10);
756
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
759   // minus one.
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));
768
769   // Initialize code pointer register.
770   __ Mov(code_pointer(), Operand(masm_->CodeObject()));
771
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');
776   __ B(&start_regexp);
777
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);
786   }
787
788   // Initialize backtrack stack pointer.
789   __ Ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackBase));
790
791   // Execute
792   __ B(&start_label_);
793
794   if (backtrack_label_.is_linked()) {
795     __ Bind(&backtrack_label_);
796     Backtrack();
797   }
798
799   if (success_label_.is_linked()) {
800     Register first_capture_start = w15;
801
802     // Save captures when successful.
803     __ Bind(&success_label_);
804
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;
810
811       // Copy captures to output.
812
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);
819       }
820       // input_start has a start_offset offset on entry. We need to include
821       // it when computing the length of the whole string.
822       if (mode_ == UC16) {
823         __ Add(input_length, start_offset(), Operand(w10, LSR, 1));
824       } else {
825         __ Add(input_length, start_offset(), w10);
826       }
827
828       // Copy the results to the output array from the cached registers first.
829       for (int i = 0;
830            (i < num_saved_registers_) && (i < kNumCachedRegisters);
831            i += 2) {
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);
837         }
838         // Offsets need to be relative to the start of the string.
839         if (mode_ == UC16) {
840           __ Add(capture_start, input_length, Operand(capture_start, ASR, 1));
841           __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
842         } else {
843           __ Add(capture_start, input_length, capture_start);
844           __ Add(capture_end, input_length, capture_end);
845         }
846         // The output pointer advances for a possible global match.
847         __ Stp(capture_start,
848                capture_end,
849                MemOperand(output_array(), kPointerSize, PostIndex));
850       }
851
852       // Only carry on if there are more than kNumCachedRegisters capture
853       // registers.
854       int num_registers_left_on_stack =
855           num_saved_registers_ - kNumCachedRegisters;
856       if (num_registers_left_on_stack > 0) {
857         Register base = x10;
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);
862
863         // We can unroll the loop here, we should not unroll for less than 2
864         // registers.
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++) {
868             __ Ldp(capture_end,
869                    capture_start,
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);
874             }
875             // Offsets need to be relative to the start of the string.
876             if (mode_ == UC16) {
877               __ Add(capture_start,
878                      input_length,
879                      Operand(capture_start, ASR, 1));
880               __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
881             } else {
882               __ Add(capture_start, input_length, capture_start);
883               __ Add(capture_end, input_length, capture_end);
884             }
885             // The output pointer advances for a possible global match.
886             __ Stp(capture_start,
887                    capture_end,
888                    MemOperand(output_array(), kPointerSize, PostIndex));
889           }
890         } else {
891           Label loop, start;
892           __ Mov(x11, num_registers_left_on_stack);
893
894           __ Ldp(capture_end,
895                  capture_start,
896                  MemOperand(base, -kPointerSize, PostIndex));
897           if (global_with_zero_length_check()) {
898             __ Mov(first_capture_start, capture_start);
899           }
900           __ B(&start);
901
902           __ Bind(&loop);
903           __ Ldp(capture_end,
904                  capture_start,
905                  MemOperand(base, -kPointerSize, PostIndex));
906           __ Bind(&start);
907           if (mode_ == UC16) {
908             __ Add(capture_start, input_length, Operand(capture_start, ASR, 1));
909             __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
910           } else {
911             __ Add(capture_start, input_length, capture_start);
912             __ Add(capture_end, input_length, capture_end);
913           }
914           // The output pointer advances for a possible global match.
915           __ Stp(capture_start,
916                  capture_end,
917                  MemOperand(output_array(), kPointerSize, PostIndex));
918           __ Sub(x11, x11, 2);
919           __ Cbnz(x11, &loop);
920         }
921       }
922     }
923
924     if (global()) {
925       Register success_counter = w0;
926       Register output_size = x10;
927       // Restart matching if the regular expression is flagged as global.
928
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));
933
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);
941
942       // The output pointer is already set to the next field in the output
943       // array.
944       // Update output size on the frame before we restart matching.
945       __ Str(output_size, MemOperand(frame_pointer(), kOutputSize));
946
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));
958       }
959
960       __ B(&load_char_start_regexp);
961     } else {
962       __ Mov(w0, SUCCESS);
963     }
964   }
965
966   if (exit_label_.is_linked()) {
967     // Exit and return w0
968     __ Bind(&exit_label_);
969     if (global()) {
970       __ Ldr(w0, MemOperand(frame_pointer(), kSuccessCounter));
971     }
972   }
973
974   __ Bind(&return_w0);
975
976   // Set stack pointer back to first register to retain
977   ASSERT(csp.Is(__ StackPointer()));
978   __ Mov(csp, fp);
979
980   // Restore registers.
981   __ PopCPURegList(registers_to_retain);
982
983   __ Ret();
984
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);
990
991   if (check_preempt_label_.is_linked()) {
992     __ Bind(&check_preempt_label_);
993     SaveLinkRegister();
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();
1003     __ Ret();
1004   }
1005
1006   if (stack_overflow_label_.is_linked()) {
1007     __ Bind(&stack_overflow_label_);
1008     SaveLinkRegister();
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();
1028     __ Ret();
1029   }
1030
1031   if (exit_with_exception.is_linked()) {
1032     __ Bind(&exit_with_exception);
1033     __ Mov(w0, EXCEPTION);
1034     __ B(&return_w0);
1035   }
1036
1037   CodeDesc code_desc;
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);
1043 }
1044
1045
1046 void RegExpMacroAssemblerARM64::GoTo(Label* to) {
1047   BranchOrBacktrack(al, to);
1048 }
1049
1050 void RegExpMacroAssemblerARM64::IfRegisterGE(int reg, int comparand,
1051                                              Label* if_ge) {
1052   Register to_compare = GetRegister(reg, w10);
1053   CompareAndBranchOrBacktrack(to_compare, comparand, ge, if_ge);
1054 }
1055
1056
1057 void RegExpMacroAssemblerARM64::IfRegisterLT(int reg, int comparand,
1058                                              Label* if_lt) {
1059   Register to_compare = GetRegister(reg, w10);
1060   CompareAndBranchOrBacktrack(to_compare, comparand, lt, if_lt);
1061 }
1062
1063
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);
1068 }
1069
1070 RegExpMacroAssembler::IrregexpImplementation
1071     RegExpMacroAssemblerARM64::Implementation() {
1072   return kARM64Implementation;
1073 }
1074
1075
1076 void RegExpMacroAssemblerARM64::LoadCurrentCharacter(int cp_offset,
1077                                                      Label* on_end_of_input,
1078                                                      bool check_bounds,
1079                                                      int characters) {
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));
1085   if (check_bounds) {
1086     CheckPosition(cp_offset + characters - 1, on_end_of_input);
1087   }
1088   LoadCurrentCharacterUnchecked(cp_offset, characters);
1089 }
1090
1091
1092 void RegExpMacroAssemblerARM64::PopCurrentPosition() {
1093   Pop(current_input_offset());
1094 }
1095
1096
1097 void RegExpMacroAssemblerARM64::PopRegister(int register_index) {
1098   Pop(w10);
1099   StoreRegister(register_index, w10);
1100 }
1101
1102
1103 void RegExpMacroAssemblerARM64::PushBacktrack(Label* label) {
1104   if (label->is_bound()) {
1105     int target = label->pos();
1106     __ Mov(w10, target + Code::kHeaderSize - kHeapObjectTag);
1107   } else {
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);
1114     }
1115   }
1116   Push(w10);
1117   CheckStackLimit();
1118 }
1119
1120
1121 void RegExpMacroAssemblerARM64::PushCurrentPosition() {
1122   Push(current_input_offset());
1123 }
1124
1125
1126 void RegExpMacroAssemblerARM64::PushRegister(int register_index,
1127                                              StackCheckFlag check_stack_limit) {
1128   Register to_push = GetRegister(register_index, w10);
1129   Push(to_push);
1130   if (check_stack_limit) CheckStackLimit();
1131 }
1132
1133
1134 void RegExpMacroAssemblerARM64::ReadCurrentPositionFromRegister(int reg) {
1135   Register cached_register;
1136   RegisterState register_state = GetRegisterState(reg);
1137   switch (register_state) {
1138     case STACKED:
1139       __ Ldr(current_input_offset(), register_location(reg));
1140       break;
1141     case CACHED_LSW:
1142       cached_register = GetCachedRegister(reg);
1143       __ Mov(current_input_offset(), cached_register.W());
1144       break;
1145     case CACHED_MSW:
1146       cached_register = GetCachedRegister(reg);
1147       __ Lsr(current_input_offset().X(), cached_register, kWRegSizeInBits);
1148       break;
1149     default:
1150       UNREACHABLE();
1151       break;
1152   }
1153 }
1154
1155
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));
1160 }
1161
1162
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);
1173 }
1174
1175
1176 void RegExpMacroAssemblerARM64::SetRegister(int register_index, int to) {
1177   ASSERT(register_index >= num_saved_registers_);  // Reserved for positions!
1178   Register set_to = wzr;
1179   if (to != 0) {
1180     set_to = w10;
1181     __ Mov(set_to, to);
1182   }
1183   StoreRegister(register_index, set_to);
1184 }
1185
1186
1187 bool RegExpMacroAssemblerARM64::Succeed() {
1188   __ B(&success_label_);
1189   return global();
1190 }
1191
1192
1193 void RegExpMacroAssemblerARM64::WriteCurrentPositionToRegister(int reg,
1194                                                                int cp_offset) {
1195   Register position = current_input_offset();
1196   if (cp_offset != 0) {
1197     position = w10;
1198     __ Add(position, current_input_offset(), cp_offset * char_size());
1199   }
1200   StoreRegister(reg, position);
1201 }
1202
1203
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;
1207
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());
1212     num_registers--;
1213     reg_from++;
1214   }
1215
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());
1220     reg_from += 2;
1221     num_registers -= 2;
1222   }
1223
1224   if ((num_registers % 2) == 1) {
1225     StoreRegister(reg_from, non_position_value());
1226     num_registers--;
1227     reg_from++;
1228   }
1229
1230   if (num_registers > 0) {
1231     // If there are some remaining registers, they are stored on the stack.
1232     ASSERT(reg_from >= kNumCachedRegisters);
1233
1234     // Move down the indexes of the registers on stack to get the correct offset
1235     // in memory.
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);
1246
1247       Label loop;
1248       __ Mov(x11, num_registers);
1249       __ Bind(&loop);
1250       __ Str(twice_non_position_value(),
1251              MemOperand(base, -kPointerSize, PostIndex));
1252       __ Sub(x11, x11, 2);
1253       __ Cbnz(x11, &loop);
1254     } else {
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;
1259       }
1260     }
1261   }
1262 }
1263
1264
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);
1272   }
1273   StoreRegister(reg, w10);
1274 }
1275
1276
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);
1281 }
1282
1283
1284 int RegExpMacroAssemblerARM64::CheckStackGuardState(Address* return_address,
1285                                                   Code* re_code,
1286                                                   Address re_frame,
1287                                                   int start_offset,
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();
1293     return EXCEPTION;
1294   }
1295
1296   // If not real stack overflow the stack guard was used to interrupt
1297   // execution for another purpose.
1298
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) {
1302     return RETRY;
1303   }
1304
1305   // Prepare for possible GC.
1306   HandleScope handles(isolate);
1307   Handle<Code> code_handle(re_code);
1308
1309   Handle<String> subject(frame_entry<String*>(re_frame, kInput));
1310
1311   // Current string.
1312   bool is_ascii = subject->IsOneByteRepresentationUnderneath();
1313
1314   ASSERT(re_code->instruction_start() <= *return_address);
1315   ASSERT(*return_address <=
1316       re_code->instruction_start() + re_code->instruction_size());
1317
1318   Object* result = Execution::HandleStackGuardInterrupt(isolate);
1319
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;
1324   }
1325
1326   if (result->IsException()) {
1327     return EXCEPTION;
1328   }
1329
1330   Handle<String> subject_tmp = subject;
1331   int slice_offset = 0;
1332
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();
1340   }
1341
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).
1347     return RETRY;
1348   }
1349
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());
1356
1357   // The original start address of the characters to match.
1358   const byte* start_address = *input_start;
1359
1360   // Find the current start address of the same character at the current string
1361   // position.
1362   const byte* new_address = StringCharacterPosition(*subject_tmp,
1363       start_offset + slice_offset);
1364
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;
1378   }
1379
1380   return 0;
1381 }
1382
1383
1384 void RegExpMacroAssemblerARM64::CheckPosition(int cp_offset,
1385                                               Label* on_outside_input) {
1386   CompareAndBranchOrBacktrack(current_input_offset(),
1387                               -cp_offset * char_size(),
1388                               ge,
1389                               on_outside_input);
1390 }
1391
1392
1393 bool RegExpMacroAssemblerARM64::CanReadUnaligned() {
1394   // TODO(pielan): See whether or not we should disable unaligned accesses.
1395   return !slow_safe();
1396 }
1397
1398
1399 // Private methods:
1400
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;
1410
1411   ASSERT(csp.Is(__ StackPointer()));
1412   __ Claim(xreg_to_claim);
1413
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);
1419
1420   __ Mov(w3, start_offset());
1421   // RegExp code frame pointer.
1422   __ Mov(x2, frame_pointer());
1423   // Code* of self.
1424   __ Mov(x1, Operand(masm_->CodeObject()));
1425
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.
1429   __ Mov(x0, csp);
1430
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);
1436
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);
1440
1441   ASSERT(csp.Is(__ StackPointer()));
1442   __ Drop(xreg_to_claim);
1443
1444   // Reload the Code pointer.
1445   __ Mov(code_pointer(), Operand(masm_->CodeObject()));
1446 }
1447
1448 void RegExpMacroAssemblerARM64::BranchOrBacktrack(Condition condition,
1449                                                   Label* to) {
1450   if (condition == al) {  // Unconditional.
1451     if (to == NULL) {
1452       Backtrack();
1453       return;
1454     }
1455     __ B(to);
1456     return;
1457   }
1458   if (to == NULL) {
1459     to = &backtrack_label_;
1460   }
1461   // TODO(ulan): do direct jump when jump distance is known and fits in imm19.
1462   Condition inverted_condition = InvertCondition(condition);
1463   Label no_branch;
1464   __ B(inverted_condition, &no_branch);
1465   __ B(to);
1466   __ Bind(&no_branch);
1467 }
1468
1469 void RegExpMacroAssemblerARM64::CompareAndBranchOrBacktrack(Register reg,
1470                                                             int immediate,
1471                                                             Condition condition,
1472                                                             Label* to) {
1473   if ((immediate == 0) && ((condition == eq) || (condition == ne))) {
1474     if (to == NULL) {
1475       to = &backtrack_label_;
1476     }
1477     // TODO(ulan): do direct jump when jump distance is known and fits in imm19.
1478     Label no_branch;
1479     if (condition == eq) {
1480       __ Cbnz(reg, &no_branch);
1481     } else {
1482       __ Cbz(reg, &no_branch);
1483     }
1484     __ B(to);
1485     __ Bind(&no_branch);
1486   } else {
1487     __ Cmp(reg, immediate);
1488     BranchOrBacktrack(condition, to);
1489   }
1490 }
1491
1492
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()));
1500   __ Cmp(csp, x10);
1501   CallIf(&check_preempt_label_, ls);
1502 }
1503
1504
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);
1512 }
1513
1514
1515 void RegExpMacroAssemblerARM64::Push(Register source) {
1516   ASSERT(source.Is32Bits());
1517   ASSERT(!source.is(backtrack_stackpointer()));
1518   __ Str(source,
1519          MemOperand(backtrack_stackpointer(),
1520                     -static_cast<int>(kWRegSize),
1521                     PreIndex));
1522 }
1523
1524
1525 void RegExpMacroAssemblerARM64::Pop(Register target) {
1526   ASSERT(target.Is32Bits());
1527   ASSERT(!target.is(backtrack_stackpointer()));
1528   __ Ldr(target,
1529          MemOperand(backtrack_stackpointer(), kWRegSize, PostIndex));
1530 }
1531
1532
1533 Register RegExpMacroAssemblerARM64::GetCachedRegister(int register_index) {
1534   ASSERT(register_index < kNumCachedRegisters);
1535   return Register::Create(register_index / 2, kXRegSizeInBits);
1536 }
1537
1538
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;
1545   }
1546   Register result;
1547   RegisterState register_state = GetRegisterState(register_index);
1548   switch (register_state) {
1549     case STACKED:
1550       __ Ldr(maybe_result, register_location(register_index));
1551       result = maybe_result;
1552       break;
1553     case CACHED_LSW:
1554       result = GetCachedRegister(register_index).W();
1555       break;
1556     case CACHED_MSW:
1557       __ Lsr(maybe_result.X(), GetCachedRegister(register_index),
1558              kWRegSizeInBits);
1559       result = maybe_result;
1560       break;
1561     default:
1562       UNREACHABLE();
1563       break;
1564   }
1565   ASSERT(result.Is32Bits());
1566   return result;
1567 }
1568
1569
1570 void RegExpMacroAssemblerARM64::StoreRegister(int register_index,
1571                                               Register source) {
1572   ASSERT(source.Is32Bits());
1573   ASSERT(register_index >= 0);
1574   if (num_registers_ <= register_index) {
1575     num_registers_ = register_index + 1;
1576   }
1577
1578   Register cached_register;
1579   RegisterState register_state = GetRegisterState(register_index);
1580   switch (register_state) {
1581     case STACKED:
1582       __ Str(source, register_location(register_index));
1583       break;
1584     case CACHED_LSW:
1585       cached_register = GetCachedRegister(register_index);
1586       if (!source.Is(cached_register.W())) {
1587         __ Bfi(cached_register, source.X(), 0, kWRegSizeInBits);
1588       }
1589       break;
1590     case CACHED_MSW:
1591       cached_register = GetCachedRegister(register_index);
1592       __ Bfi(cached_register, source.X(), kWRegSizeInBits, kWRegSizeInBits);
1593       break;
1594     default:
1595       UNREACHABLE();
1596       break;
1597   }
1598 }
1599
1600
1601 void RegExpMacroAssemblerARM64::CallIf(Label* to, Condition condition) {
1602   Label skip_call;
1603   if (condition != al) __ B(&skip_call, InvertCondition(condition));
1604   __ Bl(to);
1605   __ Bind(&skip_call);
1606 }
1607
1608
1609 void RegExpMacroAssemblerARM64::RestoreLinkRegister() {
1610   ASSERT(csp.Is(__ StackPointer()));
1611   __ Pop(lr, xzr);
1612   __ Add(lr, lr, Operand(masm_->CodeObject()));
1613 }
1614
1615
1616 void RegExpMacroAssemblerARM64::SaveLinkRegister() {
1617   ASSERT(csp.Is(__ StackPointer()));
1618   __ Sub(lr, lr, Operand(masm_->CodeObject()));
1619   __ Push(xzr, lr);
1620 }
1621
1622
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;
1628   }
1629   register_index -= kNumCachedRegisters;
1630   int offset = kFirstRegisterOnStack - register_index * kWRegSize;
1631   return MemOperand(frame_pointer(), offset);
1632 }
1633
1634 MemOperand RegExpMacroAssemblerARM64::capture_location(int register_index,
1635                                                      Register scratch) {
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);
1646   } else {
1647     __ Add(scratch, frame_pointer(), offset);
1648     return MemOperand(scratch);
1649   }
1650 }
1651
1652 void RegExpMacroAssemblerARM64::LoadCurrentCharacterUnchecked(int cp_offset,
1653                                                               int characters) {
1654   Register offset = current_input_offset();
1655
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.
1660
1661   // ARMv8 supports unaligned accesses but V8 or the kernel can decide to
1662   // disable it.
1663   // TODO(pielan): See whether or not we should disable unaligned accesses.
1664   if (!CanReadUnaligned()) {
1665     ASSERT(characters == 1);
1666   }
1667
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);
1675     } else {
1676       __ Add(w10, current_input_offset(), cp_offset * char_size());
1677     }
1678     offset = w10;
1679   }
1680
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));
1686     } else {
1687       ASSERT(characters == 1);
1688       __ Ldrb(current_character(), MemOperand(input_end(), offset, SXTW));
1689     }
1690   } else {
1691     ASSERT(mode_ == UC16);
1692     if (characters == 2) {
1693       __ Ldr(current_character(), MemOperand(input_end(), offset, SXTW));
1694     } else {
1695       ASSERT(characters == 1);
1696       __ Ldrh(current_character(), MemOperand(input_end(), offset, SXTW));
1697     }
1698   }
1699 }
1700
1701 #endif  // V8_INTERPRETED_REGEXP
1702
1703 }}  // namespace v8::internal
1704
1705 #endif  // V8_TARGET_ARCH_ARM64