• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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 #if V8_TARGET_ARCH_X64
6 
7 #include "src/regexp/x64/regexp-macro-assembler-x64.h"
8 
9 #include "src/factory.h"
10 #include "src/log.h"
11 #include "src/macro-assembler.h"
12 #include "src/objects-inl.h"
13 #include "src/regexp/regexp-macro-assembler.h"
14 #include "src/regexp/regexp-stack.h"
15 #include "src/unicode.h"
16 
17 namespace v8 {
18 namespace internal {
19 
20 #ifndef V8_INTERPRETED_REGEXP
21 
22 /*
23  * This assembler uses the following register assignment convention
24  * - rdx : Currently loaded character(s) as Latin1 or UC16.  Must be loaded
25  *         using LoadCurrentCharacter before using any of the dispatch methods.
26  *         Temporarily stores the index of capture start after a matching pass
27  *         for a global regexp.
28  * - rdi : Current position in input, as negative offset from end of string.
29  *         Please notice that this is the byte offset, not the character
30  *         offset!  Is always a 32-bit signed (negative) offset, but must be
31  *         maintained sign-extended to 64 bits, since it is used as index.
32  * - rsi : End of input (points to byte after last character in input),
33  *         so that rsi+rdi points to the current character.
34  * - rbp : Frame pointer.  Used to access arguments, local variables and
35  *         RegExp registers.
36  * - rsp : Points to tip of C stack.
37  * - rcx : Points to tip of backtrack stack.  The backtrack stack contains
38  *         only 32-bit values.  Most are offsets from some base (e.g., character
39  *         positions from end of string or code location from Code* pointer).
40  * - r8  : Code object pointer.  Used to convert between absolute and
41  *         code-object-relative addresses.
42  *
43  * The registers rax, rbx, r9 and r11 are free to use for computations.
44  * If changed to use r12+, they should be saved as callee-save registers.
45  * The macro assembler special register r13 (kRootRegister) isn't special
46  * during execution of RegExp code (it doesn't hold the value assumed when
47  * creating JS code), so Root related macro operations can be used.
48  *
49  * Each call to a C++ method should retain these registers.
50  *
51  * The stack will have the following content, in some order, indexable from the
52  * frame pointer (see, e.g., kStackHighEnd):
53  *    - Isolate* isolate     (address of the current isolate)
54  *    - direct_call          (if 1, direct call from JavaScript code, if 0 call
55  *                            through the runtime system)
56  *    - stack_area_base      (high end of the memory area to use as
57  *                            backtracking stack)
58  *    - capture array size   (may fit multiple sets of matches)
59  *    - int* capture_array   (int[num_saved_registers_], for output).
60  *    - end of input         (address of end of string)
61  *    - start of input       (address of first character in string)
62  *    - start index          (character index of start)
63  *    - String* input_string (input string)
64  *    - return address
65  *    - backup of callee save registers (rbx, possibly rsi and rdi).
66  *    - success counter      (only useful for global regexp to count matches)
67  *    - Offset of location before start of input (effectively character
68  *      string start - 1).  Used to initialize capture registers to a
69  *      non-position.
70  *    - At start of string (if 1, we are starting at the start of the
71  *      string, otherwise 0)
72  *    - register 0  rbp[-n]   (Only positions must be stored in the first
73  *    - register 1  rbp[-n-8]  num_saved_registers_ registers)
74  *    - ...
75  *
76  * The first num_saved_registers_ registers are initialized to point to
77  * "character -1" in the string (i.e., char_size() bytes before the first
78  * character of the string).  The remaining registers starts out uninitialized.
79  *
80  * The first seven values must be provided by the calling code by
81  * calling the code's entry address cast to a function pointer with the
82  * following signature:
83  * int (*match)(String* input_string,
84  *              int start_index,
85  *              Address start,
86  *              Address end,
87  *              int* capture_output_array,
88  *              bool at_start,
89  *              byte* stack_area_base,
90  *              bool direct_call)
91  */
92 
93 #define __ ACCESS_MASM((&masm_))
94 
RegExpMacroAssemblerX64(Isolate * isolate,Zone * zone,Mode mode,int registers_to_save)95 RegExpMacroAssemblerX64::RegExpMacroAssemblerX64(Isolate* isolate, Zone* zone,
96                                                  Mode mode,
97                                                  int registers_to_save)
98     : NativeRegExpMacroAssembler(isolate, zone),
99       masm_(isolate, NULL, kRegExpCodeSize, CodeObjectRequired::kYes),
100       no_root_array_scope_(&masm_),
101       code_relative_fixup_positions_(4, zone),
102       mode_(mode),
103       num_registers_(registers_to_save),
104       num_saved_registers_(registers_to_save),
105       entry_label_(),
106       start_label_(),
107       success_label_(),
108       backtrack_label_(),
109       exit_label_() {
110   DCHECK_EQ(0, registers_to_save % 2);
111   __ jmp(&entry_label_);   // We'll write the entry code when we know more.
112   __ bind(&start_label_);  // And then continue from here.
113 }
114 
115 
~RegExpMacroAssemblerX64()116 RegExpMacroAssemblerX64::~RegExpMacroAssemblerX64() {
117   // Unuse labels in case we throw away the assembler without calling GetCode.
118   entry_label_.Unuse();
119   start_label_.Unuse();
120   success_label_.Unuse();
121   backtrack_label_.Unuse();
122   exit_label_.Unuse();
123   check_preempt_label_.Unuse();
124   stack_overflow_label_.Unuse();
125 }
126 
127 
stack_limit_slack()128 int RegExpMacroAssemblerX64::stack_limit_slack()  {
129   return RegExpStack::kStackLimitSlack;
130 }
131 
132 
AdvanceCurrentPosition(int by)133 void RegExpMacroAssemblerX64::AdvanceCurrentPosition(int by) {
134   if (by != 0) {
135     __ addq(rdi, Immediate(by * char_size()));
136   }
137 }
138 
139 
AdvanceRegister(int reg,int by)140 void RegExpMacroAssemblerX64::AdvanceRegister(int reg, int by) {
141   DCHECK(reg >= 0);
142   DCHECK(reg < num_registers_);
143   if (by != 0) {
144     __ addp(register_location(reg), Immediate(by));
145   }
146 }
147 
148 
Backtrack()149 void RegExpMacroAssemblerX64::Backtrack() {
150   CheckPreemption();
151   // Pop Code* offset from backtrack stack, add Code* and jump to location.
152   Pop(rbx);
153   __ addp(rbx, code_object_pointer());
154   __ jmp(rbx);
155 }
156 
157 
Bind(Label * label)158 void RegExpMacroAssemblerX64::Bind(Label* label) {
159   __ bind(label);
160 }
161 
162 
CheckCharacter(uint32_t c,Label * on_equal)163 void RegExpMacroAssemblerX64::CheckCharacter(uint32_t c, Label* on_equal) {
164   __ cmpl(current_character(), Immediate(c));
165   BranchOrBacktrack(equal, on_equal);
166 }
167 
168 
CheckCharacterGT(uc16 limit,Label * on_greater)169 void RegExpMacroAssemblerX64::CheckCharacterGT(uc16 limit, Label* on_greater) {
170   __ cmpl(current_character(), Immediate(limit));
171   BranchOrBacktrack(greater, on_greater);
172 }
173 
174 
CheckAtStart(Label * on_at_start)175 void RegExpMacroAssemblerX64::CheckAtStart(Label* on_at_start) {
176   __ leap(rax, Operand(rdi, -char_size()));
177   __ cmpp(rax, Operand(rbp, kStringStartMinusOne));
178   BranchOrBacktrack(equal, on_at_start);
179 }
180 
181 
CheckNotAtStart(int cp_offset,Label * on_not_at_start)182 void RegExpMacroAssemblerX64::CheckNotAtStart(int cp_offset,
183                                               Label* on_not_at_start) {
184   __ leap(rax, Operand(rdi, -char_size() + cp_offset * char_size()));
185   __ cmpp(rax, Operand(rbp, kStringStartMinusOne));
186   BranchOrBacktrack(not_equal, on_not_at_start);
187 }
188 
189 
CheckCharacterLT(uc16 limit,Label * on_less)190 void RegExpMacroAssemblerX64::CheckCharacterLT(uc16 limit, Label* on_less) {
191   __ cmpl(current_character(), Immediate(limit));
192   BranchOrBacktrack(less, on_less);
193 }
194 
195 
CheckGreedyLoop(Label * on_equal)196 void RegExpMacroAssemblerX64::CheckGreedyLoop(Label* on_equal) {
197   Label fallthrough;
198   __ cmpl(rdi, Operand(backtrack_stackpointer(), 0));
199   __ j(not_equal, &fallthrough);
200   Drop();
201   BranchOrBacktrack(no_condition, on_equal);
202   __ bind(&fallthrough);
203 }
204 
205 
CheckNotBackReferenceIgnoreCase(int start_reg,bool read_backward,bool unicode,Label * on_no_match)206 void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
207     int start_reg, bool read_backward, bool unicode, Label* on_no_match) {
208   Label fallthrough;
209   ReadPositionFromRegister(rdx, start_reg);  // Offset of start of capture
210   ReadPositionFromRegister(rbx, start_reg + 1);  // Offset of end of capture
211   __ subp(rbx, rdx);  // Length of capture.
212 
213   // -----------------------
214   // rdx  = Start offset of capture.
215   // rbx = Length of capture
216 
217   // At this point, the capture registers are either both set or both cleared.
218   // If the capture length is zero, then the capture is either empty or cleared.
219   // Fall through in both cases.
220   __ j(equal, &fallthrough);
221 
222   // -----------------------
223   // rdx - Start of capture
224   // rbx - length of capture
225   // Check that there are sufficient characters left in the input.
226   if (read_backward) {
227     __ movl(rax, Operand(rbp, kStringStartMinusOne));
228     __ addl(rax, rbx);
229     __ cmpl(rdi, rax);
230     BranchOrBacktrack(less_equal, on_no_match);
231   } else {
232     __ movl(rax, rdi);
233     __ addl(rax, rbx);
234     BranchOrBacktrack(greater, on_no_match);
235   }
236 
237   if (mode_ == LATIN1) {
238     Label loop_increment;
239     if (on_no_match == NULL) {
240       on_no_match = &backtrack_label_;
241     }
242 
243     __ leap(r9, Operand(rsi, rdx, times_1, 0));
244     __ leap(r11, Operand(rsi, rdi, times_1, 0));
245     if (read_backward) {
246       __ subp(r11, rbx);  // Offset by length when matching backwards.
247     }
248     __ addp(rbx, r9);  // End of capture
249     // ---------------------
250     // r11 - current input character address
251     // r9 - current capture character address
252     // rbx - end of capture
253 
254     Label loop;
255     __ bind(&loop);
256     __ movzxbl(rdx, Operand(r9, 0));
257     __ movzxbl(rax, Operand(r11, 0));
258     // al - input character
259     // dl - capture character
260     __ cmpb(rax, rdx);
261     __ j(equal, &loop_increment);
262 
263     // Mismatch, try case-insensitive match (converting letters to lower-case).
264     // I.e., if or-ing with 0x20 makes values equal and in range 'a'-'z', it's
265     // a match.
266     __ orp(rax, Immediate(0x20));  // Convert match character to lower-case.
267     __ orp(rdx, Immediate(0x20));  // Convert capture character to lower-case.
268     __ cmpb(rax, rdx);
269     __ j(not_equal, on_no_match);  // Definitely not equal.
270     __ subb(rax, Immediate('a'));
271     __ cmpb(rax, Immediate('z' - 'a'));
272     __ j(below_equal, &loop_increment);  // In range 'a'-'z'.
273     // Latin-1: Check for values in range [224,254] but not 247.
274     __ subb(rax, Immediate(224 - 'a'));
275     __ cmpb(rax, Immediate(254 - 224));
276     __ j(above, on_no_match);  // Weren't Latin-1 letters.
277     __ cmpb(rax, Immediate(247 - 224));  // Check for 247.
278     __ j(equal, on_no_match);
279     __ bind(&loop_increment);
280     // Increment pointers into match and capture strings.
281     __ addp(r11, Immediate(1));
282     __ addp(r9, Immediate(1));
283     // Compare to end of capture, and loop if not done.
284     __ cmpp(r9, rbx);
285     __ j(below, &loop);
286 
287     // Compute new value of character position after the matched part.
288     __ movp(rdi, r11);
289     __ subq(rdi, rsi);
290     if (read_backward) {
291       // Subtract match length if we matched backward.
292       __ addq(rdi, register_location(start_reg));
293       __ subq(rdi, register_location(start_reg + 1));
294     }
295   } else {
296     DCHECK(mode_ == UC16);
297     // Save important/volatile registers before calling C function.
298 #ifndef _WIN64
299     // Caller save on Linux and callee save in Windows.
300     __ pushq(rsi);
301     __ pushq(rdi);
302 #endif
303     __ pushq(backtrack_stackpointer());
304 
305     static const int num_arguments = 4;
306     __ PrepareCallCFunction(num_arguments);
307 
308     // Put arguments into parameter registers. Parameters are
309     //   Address byte_offset1 - Address captured substring's start.
310     //   Address byte_offset2 - Address of current character position.
311     //   size_t byte_length - length of capture in bytes(!)
312 //   Isolate* isolate or 0 if unicode flag.
313 #ifdef _WIN64
314     DCHECK(rcx.is(arg_reg_1));
315     DCHECK(rdx.is(arg_reg_2));
316     // Compute and set byte_offset1 (start of capture).
317     __ leap(rcx, Operand(rsi, rdx, times_1, 0));
318     // Set byte_offset2.
319     __ leap(rdx, Operand(rsi, rdi, times_1, 0));
320     if (read_backward) {
321       __ subq(rdx, rbx);
322     }
323 #else  // AMD64 calling convention
324     DCHECK(rdi.is(arg_reg_1));
325     DCHECK(rsi.is(arg_reg_2));
326     // Compute byte_offset2 (current position = rsi+rdi).
327     __ leap(rax, Operand(rsi, rdi, times_1, 0));
328     // Compute and set byte_offset1 (start of capture).
329     __ leap(rdi, Operand(rsi, rdx, times_1, 0));
330     // Set byte_offset2.
331     __ movp(rsi, rax);
332     if (read_backward) {
333       __ subq(rsi, rbx);
334     }
335 #endif  // _WIN64
336 
337     // Set byte_length.
338     __ movp(arg_reg_3, rbx);
339     // Isolate.
340 #ifdef V8_I18N_SUPPORT
341     if (unicode) {
342       __ movp(arg_reg_4, Immediate(0));
343     } else  // NOLINT
344 #endif      // V8_I18N_SUPPORT
345     {
346       __ LoadAddress(arg_reg_4, ExternalReference::isolate_address(isolate()));
347     }
348 
349     { // NOLINT: Can't find a way to open this scope without confusing the
350       // linter.
351       AllowExternalCallThatCantCauseGC scope(&masm_);
352       ExternalReference compare =
353           ExternalReference::re_case_insensitive_compare_uc16(isolate());
354       __ CallCFunction(compare, num_arguments);
355     }
356 
357     // Restore original values before reacting on result value.
358     __ Move(code_object_pointer(), masm_.CodeObject());
359     __ popq(backtrack_stackpointer());
360 #ifndef _WIN64
361     __ popq(rdi);
362     __ popq(rsi);
363 #endif
364 
365     // Check if function returned non-zero for success or zero for failure.
366     __ testp(rax, rax);
367     BranchOrBacktrack(zero, on_no_match);
368     // On success, advance position by length of capture.
369     // Requires that rbx is callee save (true for both Win64 and AMD64 ABIs).
370     if (read_backward) {
371       __ subq(rdi, rbx);
372     } else {
373       __ addq(rdi, rbx);
374     }
375   }
376   __ bind(&fallthrough);
377 }
378 
379 
CheckNotBackReference(int start_reg,bool read_backward,Label * on_no_match)380 void RegExpMacroAssemblerX64::CheckNotBackReference(int start_reg,
381                                                     bool read_backward,
382                                                     Label* on_no_match) {
383   Label fallthrough;
384 
385   // Find length of back-referenced capture.
386   ReadPositionFromRegister(rdx, start_reg);  // Offset of start of capture
387   ReadPositionFromRegister(rax, start_reg + 1);  // Offset of end of capture
388   __ subp(rax, rdx);  // Length to check.
389 
390   // At this point, the capture registers are either both set or both cleared.
391   // If the capture length is zero, then the capture is either empty or cleared.
392   // Fall through in both cases.
393   __ j(equal, &fallthrough);
394 
395   // -----------------------
396   // rdx - Start of capture
397   // rax - length of capture
398   // Check that there are sufficient characters left in the input.
399   if (read_backward) {
400     __ movl(rbx, Operand(rbp, kStringStartMinusOne));
401     __ addl(rbx, rax);
402     __ cmpl(rdi, rbx);
403     BranchOrBacktrack(less_equal, on_no_match);
404   } else {
405     __ movl(rbx, rdi);
406     __ addl(rbx, rax);
407     BranchOrBacktrack(greater, on_no_match);
408   }
409 
410   // Compute pointers to match string and capture string
411   __ leap(rbx, Operand(rsi, rdi, times_1, 0));  // Start of match.
412   if (read_backward) {
413     __ subq(rbx, rax);  // Offset by length when matching backwards.
414   }
415   __ addp(rdx, rsi);  // Start of capture.
416   __ leap(r9, Operand(rdx, rax, times_1, 0));  // End of capture
417 
418   // -----------------------
419   // rbx - current capture character address.
420   // rbx - current input character address .
421   // r9 - end of input to match (capture length after rbx).
422 
423   Label loop;
424   __ bind(&loop);
425   if (mode_ == LATIN1) {
426     __ movzxbl(rax, Operand(rdx, 0));
427     __ cmpb(rax, Operand(rbx, 0));
428   } else {
429     DCHECK(mode_ == UC16);
430     __ movzxwl(rax, Operand(rdx, 0));
431     __ cmpw(rax, Operand(rbx, 0));
432   }
433   BranchOrBacktrack(not_equal, on_no_match);
434   // Increment pointers into capture and match string.
435   __ addp(rbx, Immediate(char_size()));
436   __ addp(rdx, Immediate(char_size()));
437   // Check if we have reached end of match area.
438   __ cmpp(rdx, r9);
439   __ j(below, &loop);
440 
441   // Success.
442   // Set current character position to position after match.
443   __ movp(rdi, rbx);
444   __ subq(rdi, rsi);
445   if (read_backward) {
446     // Subtract match length if we matched backward.
447     __ addq(rdi, register_location(start_reg));
448     __ subq(rdi, register_location(start_reg + 1));
449   }
450 
451   __ bind(&fallthrough);
452 }
453 
454 
CheckNotCharacter(uint32_t c,Label * on_not_equal)455 void RegExpMacroAssemblerX64::CheckNotCharacter(uint32_t c,
456                                                 Label* on_not_equal) {
457   __ cmpl(current_character(), Immediate(c));
458   BranchOrBacktrack(not_equal, on_not_equal);
459 }
460 
461 
CheckCharacterAfterAnd(uint32_t c,uint32_t mask,Label * on_equal)462 void RegExpMacroAssemblerX64::CheckCharacterAfterAnd(uint32_t c,
463                                                      uint32_t mask,
464                                                      Label* on_equal) {
465   if (c == 0) {
466     __ testl(current_character(), Immediate(mask));
467   } else {
468     __ movl(rax, Immediate(mask));
469     __ andp(rax, current_character());
470     __ cmpl(rax, Immediate(c));
471   }
472   BranchOrBacktrack(equal, on_equal);
473 }
474 
475 
CheckNotCharacterAfterAnd(uint32_t c,uint32_t mask,Label * on_not_equal)476 void RegExpMacroAssemblerX64::CheckNotCharacterAfterAnd(uint32_t c,
477                                                         uint32_t mask,
478                                                         Label* on_not_equal) {
479   if (c == 0) {
480     __ testl(current_character(), Immediate(mask));
481   } else {
482     __ movl(rax, Immediate(mask));
483     __ andp(rax, current_character());
484     __ cmpl(rax, Immediate(c));
485   }
486   BranchOrBacktrack(not_equal, on_not_equal);
487 }
488 
489 
CheckNotCharacterAfterMinusAnd(uc16 c,uc16 minus,uc16 mask,Label * on_not_equal)490 void RegExpMacroAssemblerX64::CheckNotCharacterAfterMinusAnd(
491     uc16 c,
492     uc16 minus,
493     uc16 mask,
494     Label* on_not_equal) {
495   DCHECK(minus < String::kMaxUtf16CodeUnit);
496   __ leap(rax, Operand(current_character(), -minus));
497   __ andp(rax, Immediate(mask));
498   __ cmpl(rax, Immediate(c));
499   BranchOrBacktrack(not_equal, on_not_equal);
500 }
501 
502 
CheckCharacterInRange(uc16 from,uc16 to,Label * on_in_range)503 void RegExpMacroAssemblerX64::CheckCharacterInRange(
504     uc16 from,
505     uc16 to,
506     Label* on_in_range) {
507   __ leal(rax, Operand(current_character(), -from));
508   __ cmpl(rax, Immediate(to - from));
509   BranchOrBacktrack(below_equal, on_in_range);
510 }
511 
512 
CheckCharacterNotInRange(uc16 from,uc16 to,Label * on_not_in_range)513 void RegExpMacroAssemblerX64::CheckCharacterNotInRange(
514     uc16 from,
515     uc16 to,
516     Label* on_not_in_range) {
517   __ leal(rax, Operand(current_character(), -from));
518   __ cmpl(rax, Immediate(to - from));
519   BranchOrBacktrack(above, on_not_in_range);
520 }
521 
522 
CheckBitInTable(Handle<ByteArray> table,Label * on_bit_set)523 void RegExpMacroAssemblerX64::CheckBitInTable(
524     Handle<ByteArray> table,
525     Label* on_bit_set) {
526   __ Move(rax, table);
527   Register index = current_character();
528   if (mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) {
529     __ movp(rbx, current_character());
530     __ andp(rbx, Immediate(kTableMask));
531     index = rbx;
532   }
533   __ cmpb(FieldOperand(rax, index, times_1, ByteArray::kHeaderSize),
534           Immediate(0));
535   BranchOrBacktrack(not_equal, on_bit_set);
536 }
537 
538 
CheckSpecialCharacterClass(uc16 type,Label * on_no_match)539 bool RegExpMacroAssemblerX64::CheckSpecialCharacterClass(uc16 type,
540                                                          Label* on_no_match) {
541   // Range checks (c in min..max) are generally implemented by an unsigned
542   // (c - min) <= (max - min) check, using the sequence:
543   //   leap(rax, Operand(current_character(), -min)) or sub(rax, Immediate(min))
544   //   cmp(rax, Immediate(max - min))
545   switch (type) {
546   case 's':
547     // Match space-characters
548     if (mode_ == LATIN1) {
549       // One byte space characters are '\t'..'\r', ' ' and \u00a0.
550       Label success;
551       __ cmpl(current_character(), Immediate(' '));
552       __ j(equal, &success, Label::kNear);
553       // Check range 0x09..0x0d
554       __ leap(rax, Operand(current_character(), -'\t'));
555       __ cmpl(rax, Immediate('\r' - '\t'));
556       __ j(below_equal, &success, Label::kNear);
557       // \u00a0 (NBSP).
558       __ cmpl(rax, Immediate(0x00a0 - '\t'));
559       BranchOrBacktrack(not_equal, on_no_match);
560       __ bind(&success);
561       return true;
562     }
563     return false;
564   case 'S':
565     // The emitted code for generic character classes is good enough.
566     return false;
567   case 'd':
568     // Match ASCII digits ('0'..'9')
569     __ leap(rax, Operand(current_character(), -'0'));
570     __ cmpl(rax, Immediate('9' - '0'));
571     BranchOrBacktrack(above, on_no_match);
572     return true;
573   case 'D':
574     // Match non ASCII-digits
575     __ leap(rax, Operand(current_character(), -'0'));
576     __ cmpl(rax, Immediate('9' - '0'));
577     BranchOrBacktrack(below_equal, on_no_match);
578     return true;
579   case '.': {
580     // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
581     __ movl(rax, current_character());
582     __ xorp(rax, Immediate(0x01));
583     // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
584     __ subl(rax, Immediate(0x0b));
585     __ cmpl(rax, Immediate(0x0c - 0x0b));
586     BranchOrBacktrack(below_equal, on_no_match);
587     if (mode_ == UC16) {
588       // Compare original value to 0x2028 and 0x2029, using the already
589       // computed (current_char ^ 0x01 - 0x0b). I.e., check for
590       // 0x201d (0x2028 - 0x0b) or 0x201e.
591       __ subl(rax, Immediate(0x2028 - 0x0b));
592       __ cmpl(rax, Immediate(0x2029 - 0x2028));
593       BranchOrBacktrack(below_equal, on_no_match);
594     }
595     return true;
596   }
597   case 'n': {
598     // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
599     __ movl(rax, current_character());
600     __ xorp(rax, Immediate(0x01));
601     // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
602     __ subl(rax, Immediate(0x0b));
603     __ cmpl(rax, Immediate(0x0c - 0x0b));
604     if (mode_ == LATIN1) {
605       BranchOrBacktrack(above, on_no_match);
606     } else {
607       Label done;
608       BranchOrBacktrack(below_equal, &done);
609       // Compare original value to 0x2028 and 0x2029, using the already
610       // computed (current_char ^ 0x01 - 0x0b). I.e., check for
611       // 0x201d (0x2028 - 0x0b) or 0x201e.
612       __ subl(rax, Immediate(0x2028 - 0x0b));
613       __ cmpl(rax, Immediate(0x2029 - 0x2028));
614       BranchOrBacktrack(above, on_no_match);
615       __ bind(&done);
616     }
617     return true;
618   }
619   case 'w': {
620     if (mode_ != LATIN1) {
621       // Table is 256 entries, so all Latin1 characters can be tested.
622       __ cmpl(current_character(), Immediate('z'));
623       BranchOrBacktrack(above, on_no_match);
624     }
625     __ Move(rbx, ExternalReference::re_word_character_map());
626     DCHECK_EQ(0, word_character_map[0]);  // Character '\0' is not a word char.
627     __ testb(Operand(rbx, current_character(), times_1, 0),
628              current_character());
629     BranchOrBacktrack(zero, on_no_match);
630     return true;
631   }
632   case 'W': {
633     Label done;
634     if (mode_ != LATIN1) {
635       // Table is 256 entries, so all Latin1 characters can be tested.
636       __ cmpl(current_character(), Immediate('z'));
637       __ j(above, &done);
638     }
639     __ Move(rbx, ExternalReference::re_word_character_map());
640     DCHECK_EQ(0, word_character_map[0]);  // Character '\0' is not a word char.
641     __ testb(Operand(rbx, current_character(), times_1, 0),
642              current_character());
643     BranchOrBacktrack(not_zero, on_no_match);
644     if (mode_ != LATIN1) {
645       __ bind(&done);
646     }
647     return true;
648   }
649 
650   case '*':
651     // Match any character.
652     return true;
653   // No custom implementation (yet): s(UC16), S(UC16).
654   default:
655     return false;
656   }
657 }
658 
659 
Fail()660 void RegExpMacroAssemblerX64::Fail() {
661   STATIC_ASSERT(FAILURE == 0);  // Return value for failure is zero.
662   if (!global()) {
663     __ Set(rax, FAILURE);
664   }
665   __ jmp(&exit_label_);
666 }
667 
668 
GetCode(Handle<String> source)669 Handle<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
670   Label return_rax;
671   // Finalize code - write the entry point code now we know how many
672   // registers we need.
673   // Entry code:
674   __ bind(&entry_label_);
675 
676   // Tell the system that we have a stack frame.  Because the type is MANUAL, no
677   // is generated.
678   FrameScope scope(&masm_, StackFrame::MANUAL);
679 
680   // Actually emit code to start a new stack frame.
681   __ pushq(rbp);
682   __ movp(rbp, rsp);
683   // Save parameters and callee-save registers. Order here should correspond
684   //  to order of kBackup_ebx etc.
685 #ifdef _WIN64
686   // MSVC passes arguments in rcx, rdx, r8, r9, with backing stack slots.
687   // Store register parameters in pre-allocated stack slots,
688   __ movq(Operand(rbp, kInputString), rcx);
689   __ movq(Operand(rbp, kStartIndex), rdx);  // Passed as int32 in edx.
690   __ movq(Operand(rbp, kInputStart), r8);
691   __ movq(Operand(rbp, kInputEnd), r9);
692   // Callee-save on Win64.
693   __ pushq(rsi);
694   __ pushq(rdi);
695   __ pushq(rbx);
696 #else
697   // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9 (and then on stack).
698   // Push register parameters on stack for reference.
699   DCHECK_EQ(kInputString, -1 * kRegisterSize);
700   DCHECK_EQ(kStartIndex, -2 * kRegisterSize);
701   DCHECK_EQ(kInputStart, -3 * kRegisterSize);
702   DCHECK_EQ(kInputEnd, -4 * kRegisterSize);
703   DCHECK_EQ(kRegisterOutput, -5 * kRegisterSize);
704   DCHECK_EQ(kNumOutputRegisters, -6 * kRegisterSize);
705   __ pushq(rdi);
706   __ pushq(rsi);
707   __ pushq(rdx);
708   __ pushq(rcx);
709   __ pushq(r8);
710   __ pushq(r9);
711 
712   __ pushq(rbx);  // Callee-save
713 #endif
714 
715   __ Push(Immediate(0));  // Number of successful matches in a global regexp.
716   __ Push(Immediate(0));  // Make room for "string start - 1" constant.
717 
718   // Check if we have space on the stack for registers.
719   Label stack_limit_hit;
720   Label stack_ok;
721 
722   ExternalReference stack_limit =
723       ExternalReference::address_of_stack_limit(isolate());
724   __ movp(rcx, rsp);
725   __ Move(kScratchRegister, stack_limit);
726   __ subp(rcx, Operand(kScratchRegister, 0));
727   // Handle it if the stack pointer is already below the stack limit.
728   __ j(below_equal, &stack_limit_hit);
729   // Check if there is room for the variable number of registers above
730   // the stack limit.
731   __ cmpp(rcx, Immediate(num_registers_ * kPointerSize));
732   __ j(above_equal, &stack_ok);
733   // Exit with OutOfMemory exception. There is not enough space on the stack
734   // for our working registers.
735   __ Set(rax, EXCEPTION);
736   __ jmp(&return_rax);
737 
738   __ bind(&stack_limit_hit);
739   __ Move(code_object_pointer(), masm_.CodeObject());
740   CallCheckStackGuardState();  // Preserves no registers beside rbp and rsp.
741   __ testp(rax, rax);
742   // If returned value is non-zero, we exit with the returned value as result.
743   __ j(not_zero, &return_rax);
744 
745   __ bind(&stack_ok);
746 
747   // Allocate space on stack for registers.
748   __ subp(rsp, Immediate(num_registers_ * kPointerSize));
749   // Load string length.
750   __ movp(rsi, Operand(rbp, kInputEnd));
751   // Load input position.
752   __ movp(rdi, Operand(rbp, kInputStart));
753   // Set up rdi to be negative offset from string end.
754   __ subq(rdi, rsi);
755   // Set rax to address of char before start of the string
756   // (effectively string position -1).
757   __ movp(rbx, Operand(rbp, kStartIndex));
758   __ negq(rbx);
759   if (mode_ == UC16) {
760     __ leap(rax, Operand(rdi, rbx, times_2, -char_size()));
761   } else {
762     __ leap(rax, Operand(rdi, rbx, times_1, -char_size()));
763   }
764   // Store this value in a local variable, for use when clearing
765   // position registers.
766   __ movp(Operand(rbp, kStringStartMinusOne), rax);
767 
768 #if V8_OS_WIN
769   // Ensure that we have written to each stack page, in order. Skipping a page
770   // on Windows can cause segmentation faults. Assuming page size is 4k.
771   const int kPageSize = 4096;
772   const int kRegistersPerPage = kPageSize / kPointerSize;
773   for (int i = num_saved_registers_ + kRegistersPerPage - 1;
774       i < num_registers_;
775       i += kRegistersPerPage) {
776     __ movp(register_location(i), rax);  // One write every page.
777   }
778 #endif  // V8_OS_WIN
779 
780   // Initialize code object pointer.
781   __ Move(code_object_pointer(), masm_.CodeObject());
782 
783   Label load_char_start_regexp, start_regexp;
784   // Load newline if index is at start, previous character otherwise.
785   __ cmpl(Operand(rbp, kStartIndex), Immediate(0));
786   __ j(not_equal, &load_char_start_regexp, Label::kNear);
787   __ Set(current_character(), '\n');
788   __ jmp(&start_regexp, Label::kNear);
789 
790   // Global regexp restarts matching here.
791   __ bind(&load_char_start_regexp);
792   // Load previous char as initial value of current character register.
793   LoadCurrentCharacterUnchecked(-1, 1);
794   __ bind(&start_regexp);
795 
796   // Initialize on-stack registers.
797   if (num_saved_registers_ > 0) {
798     // Fill saved registers with initial value = start offset - 1
799     // Fill in stack push order, to avoid accessing across an unwritten
800     // page (a problem on Windows).
801     if (num_saved_registers_ > 8) {
802       __ Set(rcx, kRegisterZero);
803       Label init_loop;
804       __ bind(&init_loop);
805       __ movp(Operand(rbp, rcx, times_1, 0), rax);
806       __ subq(rcx, Immediate(kPointerSize));
807       __ cmpq(rcx,
808               Immediate(kRegisterZero - num_saved_registers_ * kPointerSize));
809       __ j(greater, &init_loop);
810     } else {  // Unroll the loop.
811       for (int i = 0; i < num_saved_registers_; i++) {
812         __ movp(register_location(i), rax);
813       }
814     }
815   }
816 
817   // Initialize backtrack stack pointer.
818   __ movp(backtrack_stackpointer(), Operand(rbp, kStackHighEnd));
819 
820   __ jmp(&start_label_);
821 
822   // Exit code:
823   if (success_label_.is_linked()) {
824     // Save captures when successful.
825     __ bind(&success_label_);
826     if (num_saved_registers_ > 0) {
827       // copy captures to output
828       __ movp(rdx, Operand(rbp, kStartIndex));
829       __ movp(rbx, Operand(rbp, kRegisterOutput));
830       __ movp(rcx, Operand(rbp, kInputEnd));
831       __ subp(rcx, Operand(rbp, kInputStart));
832       if (mode_ == UC16) {
833         __ leap(rcx, Operand(rcx, rdx, times_2, 0));
834       } else {
835         __ addp(rcx, rdx);
836       }
837       for (int i = 0; i < num_saved_registers_; i++) {
838         __ movp(rax, register_location(i));
839         if (i == 0 && global_with_zero_length_check()) {
840           // Keep capture start in rdx for the zero-length check later.
841           __ movp(rdx, rax);
842         }
843         __ addp(rax, rcx);  // Convert to index from start, not end.
844         if (mode_ == UC16) {
845           __ sarp(rax, Immediate(1));  // Convert byte index to character index.
846         }
847         __ movl(Operand(rbx, i * kIntSize), rax);
848       }
849     }
850 
851     if (global()) {
852       // Restart matching if the regular expression is flagged as global.
853       // Increment success counter.
854       __ incp(Operand(rbp, kSuccessfulCaptures));
855       // Capture results have been stored, so the number of remaining global
856       // output registers is reduced by the number of stored captures.
857       __ movsxlq(rcx, Operand(rbp, kNumOutputRegisters));
858       __ subp(rcx, Immediate(num_saved_registers_));
859       // Check whether we have enough room for another set of capture results.
860       __ cmpp(rcx, Immediate(num_saved_registers_));
861       __ j(less, &exit_label_);
862 
863       __ movp(Operand(rbp, kNumOutputRegisters), rcx);
864       // Advance the location for output.
865       __ addp(Operand(rbp, kRegisterOutput),
866               Immediate(num_saved_registers_ * kIntSize));
867 
868       // Prepare rax to initialize registers with its value in the next run.
869       __ movp(rax, Operand(rbp, kStringStartMinusOne));
870 
871       if (global_with_zero_length_check()) {
872         // Special case for zero-length matches.
873         // rdx: capture start index
874         __ cmpp(rdi, rdx);
875         // Not a zero-length match, restart.
876         __ j(not_equal, &load_char_start_regexp);
877         // rdi (offset from the end) is zero if we already reached the end.
878         __ testp(rdi, rdi);
879         __ j(zero, &exit_label_, Label::kNear);
880         // Advance current position after a zero-length match.
881         Label advance;
882         __ bind(&advance);
883         if (mode_ == UC16) {
884           __ addq(rdi, Immediate(2));
885         } else {
886           __ incq(rdi);
887         }
888         if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
889       }
890 
891       __ jmp(&load_char_start_regexp);
892     } else {
893       __ movp(rax, Immediate(SUCCESS));
894     }
895   }
896 
897   __ bind(&exit_label_);
898   if (global()) {
899     // Return the number of successful captures.
900     __ movp(rax, Operand(rbp, kSuccessfulCaptures));
901   }
902 
903   __ bind(&return_rax);
904 #ifdef _WIN64
905   // Restore callee save registers.
906   __ leap(rsp, Operand(rbp, kLastCalleeSaveRegister));
907   __ popq(rbx);
908   __ popq(rdi);
909   __ popq(rsi);
910   // Stack now at rbp.
911 #else
912   // Restore callee save register.
913   __ movp(rbx, Operand(rbp, kBackup_rbx));
914   // Skip rsp to rbp.
915   __ movp(rsp, rbp);
916 #endif
917   // Exit function frame, restore previous one.
918   __ popq(rbp);
919   __ ret(0);
920 
921   // Backtrack code (branch target for conditional backtracks).
922   if (backtrack_label_.is_linked()) {
923     __ bind(&backtrack_label_);
924     Backtrack();
925   }
926 
927   Label exit_with_exception;
928 
929   // Preempt-code
930   if (check_preempt_label_.is_linked()) {
931     SafeCallTarget(&check_preempt_label_);
932 
933     __ pushq(backtrack_stackpointer());
934     __ pushq(rdi);
935 
936     CallCheckStackGuardState();
937     __ testp(rax, rax);
938     // If returning non-zero, we should end execution with the given
939     // result as return value.
940     __ j(not_zero, &return_rax);
941 
942     // Restore registers.
943     __ Move(code_object_pointer(), masm_.CodeObject());
944     __ popq(rdi);
945     __ popq(backtrack_stackpointer());
946     // String might have moved: Reload esi from frame.
947     __ movp(rsi, Operand(rbp, kInputEnd));
948     SafeReturn();
949   }
950 
951   // Backtrack stack overflow code.
952   if (stack_overflow_label_.is_linked()) {
953     SafeCallTarget(&stack_overflow_label_);
954     // Reached if the backtrack-stack limit has been hit.
955 
956     Label grow_failed;
957     // Save registers before calling C function
958 #ifndef _WIN64
959     // Callee-save in Microsoft 64-bit ABI, but not in AMD64 ABI.
960     __ pushq(rsi);
961     __ pushq(rdi);
962 #endif
963 
964     // Call GrowStack(backtrack_stackpointer())
965     static const int num_arguments = 3;
966     __ PrepareCallCFunction(num_arguments);
967 #ifdef _WIN64
968     // Microsoft passes parameters in rcx, rdx, r8.
969     // First argument, backtrack stackpointer, is already in rcx.
970     __ leap(rdx, Operand(rbp, kStackHighEnd));  // Second argument
971     __ LoadAddress(r8, ExternalReference::isolate_address(isolate()));
972 #else
973     // AMD64 ABI passes parameters in rdi, rsi, rdx.
974     __ movp(rdi, backtrack_stackpointer());   // First argument.
975     __ leap(rsi, Operand(rbp, kStackHighEnd));  // Second argument.
976     __ LoadAddress(rdx, ExternalReference::isolate_address(isolate()));
977 #endif
978     ExternalReference grow_stack =
979         ExternalReference::re_grow_stack(isolate());
980     __ CallCFunction(grow_stack, num_arguments);
981     // If return NULL, we have failed to grow the stack, and
982     // must exit with a stack-overflow exception.
983     __ testp(rax, rax);
984     __ j(equal, &exit_with_exception);
985     // Otherwise use return value as new stack pointer.
986     __ movp(backtrack_stackpointer(), rax);
987     // Restore saved registers and continue.
988     __ Move(code_object_pointer(), masm_.CodeObject());
989 #ifndef _WIN64
990     __ popq(rdi);
991     __ popq(rsi);
992 #endif
993     SafeReturn();
994   }
995 
996   if (exit_with_exception.is_linked()) {
997     // If any of the code above needed to exit with an exception.
998     __ bind(&exit_with_exception);
999     // Exit with Result EXCEPTION(-1) to signal thrown exception.
1000     __ Set(rax, EXCEPTION);
1001     __ jmp(&return_rax);
1002   }
1003 
1004   FixupCodeRelativePositions();
1005 
1006   CodeDesc code_desc;
1007   masm_.GetCode(&code_desc);
1008   Isolate* isolate = this->isolate();
1009   Handle<Code> code = isolate->factory()->NewCode(
1010       code_desc, Code::ComputeFlags(Code::REGEXP),
1011       masm_.CodeObject());
1012   PROFILE(isolate, RegExpCodeCreateEvent(AbstractCode::cast(*code), *source));
1013   return Handle<HeapObject>::cast(code);
1014 }
1015 
1016 
GoTo(Label * to)1017 void RegExpMacroAssemblerX64::GoTo(Label* to) {
1018   BranchOrBacktrack(no_condition, to);
1019 }
1020 
1021 
IfRegisterGE(int reg,int comparand,Label * if_ge)1022 void RegExpMacroAssemblerX64::IfRegisterGE(int reg,
1023                                            int comparand,
1024                                            Label* if_ge) {
1025   __ cmpp(register_location(reg), Immediate(comparand));
1026   BranchOrBacktrack(greater_equal, if_ge);
1027 }
1028 
1029 
IfRegisterLT(int reg,int comparand,Label * if_lt)1030 void RegExpMacroAssemblerX64::IfRegisterLT(int reg,
1031                                            int comparand,
1032                                            Label* if_lt) {
1033   __ cmpp(register_location(reg), Immediate(comparand));
1034   BranchOrBacktrack(less, if_lt);
1035 }
1036 
1037 
IfRegisterEqPos(int reg,Label * if_eq)1038 void RegExpMacroAssemblerX64::IfRegisterEqPos(int reg,
1039                                               Label* if_eq) {
1040   __ cmpp(rdi, register_location(reg));
1041   BranchOrBacktrack(equal, if_eq);
1042 }
1043 
1044 
1045 RegExpMacroAssembler::IrregexpImplementation
Implementation()1046     RegExpMacroAssemblerX64::Implementation() {
1047   return kX64Implementation;
1048 }
1049 
1050 
LoadCurrentCharacter(int cp_offset,Label * on_end_of_input,bool check_bounds,int characters)1051 void RegExpMacroAssemblerX64::LoadCurrentCharacter(int cp_offset,
1052                                                    Label* on_end_of_input,
1053                                                    bool check_bounds,
1054                                                    int characters) {
1055   DCHECK(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
1056   if (check_bounds) {
1057     if (cp_offset >= 0) {
1058       CheckPosition(cp_offset + characters - 1, on_end_of_input);
1059     } else {
1060       CheckPosition(cp_offset, on_end_of_input);
1061     }
1062   }
1063   LoadCurrentCharacterUnchecked(cp_offset, characters);
1064 }
1065 
1066 
PopCurrentPosition()1067 void RegExpMacroAssemblerX64::PopCurrentPosition() {
1068   Pop(rdi);
1069 }
1070 
1071 
PopRegister(int register_index)1072 void RegExpMacroAssemblerX64::PopRegister(int register_index) {
1073   Pop(rax);
1074   __ movp(register_location(register_index), rax);
1075 }
1076 
1077 
PushBacktrack(Label * label)1078 void RegExpMacroAssemblerX64::PushBacktrack(Label* label) {
1079   Push(label);
1080   CheckStackLimit();
1081 }
1082 
1083 
PushCurrentPosition()1084 void RegExpMacroAssemblerX64::PushCurrentPosition() {
1085   Push(rdi);
1086 }
1087 
1088 
PushRegister(int register_index,StackCheckFlag check_stack_limit)1089 void RegExpMacroAssemblerX64::PushRegister(int register_index,
1090                                            StackCheckFlag check_stack_limit) {
1091   __ movp(rax, register_location(register_index));
1092   Push(rax);
1093   if (check_stack_limit) CheckStackLimit();
1094 }
1095 
1096 
1097 STATIC_ASSERT(kPointerSize == kInt64Size || kPointerSize == kInt32Size);
1098 
1099 
ReadCurrentPositionFromRegister(int reg)1100 void RegExpMacroAssemblerX64::ReadCurrentPositionFromRegister(int reg) {
1101   if (kPointerSize == kInt64Size) {
1102     __ movq(rdi, register_location(reg));
1103   } else {
1104     // Need sign extension for x32 as rdi might be used as an index register.
1105     __ movsxlq(rdi, register_location(reg));
1106   }
1107 }
1108 
1109 
ReadPositionFromRegister(Register dst,int reg)1110 void RegExpMacroAssemblerX64::ReadPositionFromRegister(Register dst, int reg) {
1111   if (kPointerSize == kInt64Size) {
1112     __ movq(dst, register_location(reg));
1113   } else {
1114     // Need sign extension for x32 as dst might be used as an index register.
1115     __ movsxlq(dst, register_location(reg));
1116   }
1117 }
1118 
1119 
ReadStackPointerFromRegister(int reg)1120 void RegExpMacroAssemblerX64::ReadStackPointerFromRegister(int reg) {
1121   __ movp(backtrack_stackpointer(), register_location(reg));
1122   __ addp(backtrack_stackpointer(), Operand(rbp, kStackHighEnd));
1123 }
1124 
1125 
SetCurrentPositionFromEnd(int by)1126 void RegExpMacroAssemblerX64::SetCurrentPositionFromEnd(int by) {
1127   Label after_position;
1128   __ cmpp(rdi, Immediate(-by * char_size()));
1129   __ j(greater_equal, &after_position, Label::kNear);
1130   __ movq(rdi, Immediate(-by * char_size()));
1131   // On RegExp code entry (where this operation is used), the character before
1132   // the current position is expected to be already loaded.
1133   // We have advanced the position, so it's safe to read backwards.
1134   LoadCurrentCharacterUnchecked(-1, 1);
1135   __ bind(&after_position);
1136 }
1137 
1138 
SetRegister(int register_index,int to)1139 void RegExpMacroAssemblerX64::SetRegister(int register_index, int to) {
1140   DCHECK(register_index >= num_saved_registers_);  // Reserved for positions!
1141   __ movp(register_location(register_index), Immediate(to));
1142 }
1143 
1144 
Succeed()1145 bool RegExpMacroAssemblerX64::Succeed() {
1146   __ jmp(&success_label_);
1147   return global();
1148 }
1149 
1150 
WriteCurrentPositionToRegister(int reg,int cp_offset)1151 void RegExpMacroAssemblerX64::WriteCurrentPositionToRegister(int reg,
1152                                                              int cp_offset) {
1153   if (cp_offset == 0) {
1154     __ movp(register_location(reg), rdi);
1155   } else {
1156     __ leap(rax, Operand(rdi, cp_offset * char_size()));
1157     __ movp(register_location(reg), rax);
1158   }
1159 }
1160 
1161 
ClearRegisters(int reg_from,int reg_to)1162 void RegExpMacroAssemblerX64::ClearRegisters(int reg_from, int reg_to) {
1163   DCHECK(reg_from <= reg_to);
1164   __ movp(rax, Operand(rbp, kStringStartMinusOne));
1165   for (int reg = reg_from; reg <= reg_to; reg++) {
1166     __ movp(register_location(reg), rax);
1167   }
1168 }
1169 
1170 
WriteStackPointerToRegister(int reg)1171 void RegExpMacroAssemblerX64::WriteStackPointerToRegister(int reg) {
1172   __ movp(rax, backtrack_stackpointer());
1173   __ subp(rax, Operand(rbp, kStackHighEnd));
1174   __ movp(register_location(reg), rax);
1175 }
1176 
1177 
1178 // Private methods:
1179 
CallCheckStackGuardState()1180 void RegExpMacroAssemblerX64::CallCheckStackGuardState() {
1181   // This function call preserves no register values. Caller should
1182   // store anything volatile in a C call or overwritten by this function.
1183   static const int num_arguments = 3;
1184   __ PrepareCallCFunction(num_arguments);
1185 #ifdef _WIN64
1186   // Second argument: Code* of self. (Do this before overwriting r8).
1187   __ movp(rdx, code_object_pointer());
1188   // Third argument: RegExp code frame pointer.
1189   __ movp(r8, rbp);
1190   // First argument: Next address on the stack (will be address of
1191   // return address).
1192   __ leap(rcx, Operand(rsp, -kPointerSize));
1193 #else
1194   // Third argument: RegExp code frame pointer.
1195   __ movp(rdx, rbp);
1196   // Second argument: Code* of self.
1197   __ movp(rsi, code_object_pointer());
1198   // First argument: Next address on the stack (will be address of
1199   // return address).
1200   __ leap(rdi, Operand(rsp, -kRegisterSize));
1201 #endif
1202   ExternalReference stack_check =
1203       ExternalReference::re_check_stack_guard_state(isolate());
1204   __ CallCFunction(stack_check, num_arguments);
1205 }
1206 
1207 
1208 // Helper function for reading a value out of a stack frame.
1209 template <typename T>
frame_entry(Address re_frame,int frame_offset)1210 static T& frame_entry(Address re_frame, int frame_offset) {
1211   return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
1212 }
1213 
1214 
1215 template <typename T>
frame_entry_address(Address re_frame,int frame_offset)1216 static T* frame_entry_address(Address re_frame, int frame_offset) {
1217   return reinterpret_cast<T*>(re_frame + frame_offset);
1218 }
1219 
1220 
CheckStackGuardState(Address * return_address,Code * re_code,Address re_frame)1221 int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
1222                                                   Code* re_code,
1223                                                   Address re_frame) {
1224   return NativeRegExpMacroAssembler::CheckStackGuardState(
1225       frame_entry<Isolate*>(re_frame, kIsolate),
1226       frame_entry<int>(re_frame, kStartIndex),
1227       frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
1228       frame_entry_address<String*>(re_frame, kInputString),
1229       frame_entry_address<const byte*>(re_frame, kInputStart),
1230       frame_entry_address<const byte*>(re_frame, kInputEnd));
1231 }
1232 
1233 
register_location(int register_index)1234 Operand RegExpMacroAssemblerX64::register_location(int register_index) {
1235   DCHECK(register_index < (1<<30));
1236   if (num_registers_ <= register_index) {
1237     num_registers_ = register_index + 1;
1238   }
1239   return Operand(rbp, kRegisterZero - register_index * kPointerSize);
1240 }
1241 
1242 
CheckPosition(int cp_offset,Label * on_outside_input)1243 void RegExpMacroAssemblerX64::CheckPosition(int cp_offset,
1244                                             Label* on_outside_input) {
1245   if (cp_offset >= 0) {
1246     __ cmpl(rdi, Immediate(-cp_offset * char_size()));
1247     BranchOrBacktrack(greater_equal, on_outside_input);
1248   } else {
1249     __ leap(rax, Operand(rdi, cp_offset * char_size()));
1250     __ cmpp(rax, Operand(rbp, kStringStartMinusOne));
1251     BranchOrBacktrack(less_equal, on_outside_input);
1252   }
1253 }
1254 
1255 
BranchOrBacktrack(Condition condition,Label * to)1256 void RegExpMacroAssemblerX64::BranchOrBacktrack(Condition condition,
1257                                                 Label* to) {
1258   if (condition < 0) {  // No condition
1259     if (to == NULL) {
1260       Backtrack();
1261       return;
1262     }
1263     __ jmp(to);
1264     return;
1265   }
1266   if (to == NULL) {
1267     __ j(condition, &backtrack_label_);
1268     return;
1269   }
1270   __ j(condition, to);
1271 }
1272 
1273 
SafeCall(Label * to)1274 void RegExpMacroAssemblerX64::SafeCall(Label* to) {
1275   __ call(to);
1276 }
1277 
1278 
SafeCallTarget(Label * label)1279 void RegExpMacroAssemblerX64::SafeCallTarget(Label* label) {
1280   __ bind(label);
1281   __ subp(Operand(rsp, 0), code_object_pointer());
1282 }
1283 
1284 
SafeReturn()1285 void RegExpMacroAssemblerX64::SafeReturn() {
1286   __ addp(Operand(rsp, 0), code_object_pointer());
1287   __ ret(0);
1288 }
1289 
1290 
Push(Register source)1291 void RegExpMacroAssemblerX64::Push(Register source) {
1292   DCHECK(!source.is(backtrack_stackpointer()));
1293   // Notice: This updates flags, unlike normal Push.
1294   __ subp(backtrack_stackpointer(), Immediate(kIntSize));
1295   __ movl(Operand(backtrack_stackpointer(), 0), source);
1296 }
1297 
1298 
Push(Immediate value)1299 void RegExpMacroAssemblerX64::Push(Immediate value) {
1300   // Notice: This updates flags, unlike normal Push.
1301   __ subp(backtrack_stackpointer(), Immediate(kIntSize));
1302   __ movl(Operand(backtrack_stackpointer(), 0), value);
1303 }
1304 
1305 
FixupCodeRelativePositions()1306 void RegExpMacroAssemblerX64::FixupCodeRelativePositions() {
1307   for (int i = 0, n = code_relative_fixup_positions_.length(); i < n; i++) {
1308     int position = code_relative_fixup_positions_[i];
1309     // The position succeeds a relative label offset from position.
1310     // Patch the relative offset to be relative to the Code object pointer
1311     // instead.
1312     int patch_position = position - kIntSize;
1313     int offset = masm_.long_at(patch_position);
1314     masm_.long_at_put(patch_position,
1315                        offset
1316                        + position
1317                        + Code::kHeaderSize
1318                        - kHeapObjectTag);
1319   }
1320   code_relative_fixup_positions_.Clear();
1321 }
1322 
1323 
Push(Label * backtrack_target)1324 void RegExpMacroAssemblerX64::Push(Label* backtrack_target) {
1325   __ subp(backtrack_stackpointer(), Immediate(kIntSize));
1326   __ movl(Operand(backtrack_stackpointer(), 0), backtrack_target);
1327   MarkPositionForCodeRelativeFixup();
1328 }
1329 
1330 
Pop(Register target)1331 void RegExpMacroAssemblerX64::Pop(Register target) {
1332   DCHECK(!target.is(backtrack_stackpointer()));
1333   __ movsxlq(target, Operand(backtrack_stackpointer(), 0));
1334   // Notice: This updates flags, unlike normal Pop.
1335   __ addp(backtrack_stackpointer(), Immediate(kIntSize));
1336 }
1337 
1338 
Drop()1339 void RegExpMacroAssemblerX64::Drop() {
1340   __ addp(backtrack_stackpointer(), Immediate(kIntSize));
1341 }
1342 
1343 
CheckPreemption()1344 void RegExpMacroAssemblerX64::CheckPreemption() {
1345   // Check for preemption.
1346   Label no_preempt;
1347   ExternalReference stack_limit =
1348       ExternalReference::address_of_stack_limit(isolate());
1349   __ load_rax(stack_limit);
1350   __ cmpp(rsp, rax);
1351   __ j(above, &no_preempt);
1352 
1353   SafeCall(&check_preempt_label_);
1354 
1355   __ bind(&no_preempt);
1356 }
1357 
1358 
CheckStackLimit()1359 void RegExpMacroAssemblerX64::CheckStackLimit() {
1360   Label no_stack_overflow;
1361   ExternalReference stack_limit =
1362       ExternalReference::address_of_regexp_stack_limit(isolate());
1363   __ load_rax(stack_limit);
1364   __ cmpp(backtrack_stackpointer(), rax);
1365   __ j(above, &no_stack_overflow);
1366 
1367   SafeCall(&stack_overflow_label_);
1368 
1369   __ bind(&no_stack_overflow);
1370 }
1371 
1372 
LoadCurrentCharacterUnchecked(int cp_offset,int characters)1373 void RegExpMacroAssemblerX64::LoadCurrentCharacterUnchecked(int cp_offset,
1374                                                             int characters) {
1375   if (mode_ == LATIN1) {
1376     if (characters == 4) {
1377       __ movl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1378     } else if (characters == 2) {
1379       __ movzxwl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1380     } else {
1381       DCHECK(characters == 1);
1382       __ movzxbl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1383     }
1384   } else {
1385     DCHECK(mode_ == UC16);
1386     if (characters == 2) {
1387       __ movl(current_character(),
1388               Operand(rsi, rdi, times_1, cp_offset * sizeof(uc16)));
1389     } else {
1390       DCHECK(characters == 1);
1391       __ movzxwl(current_character(),
1392                  Operand(rsi, rdi, times_1, cp_offset * sizeof(uc16)));
1393     }
1394   }
1395 }
1396 
1397 #undef __
1398 
1399 #endif  // V8_INTERPRETED_REGEXP
1400 
1401 }  // namespace internal
1402 }  // namespace v8
1403 
1404 #endif  // V8_TARGET_ARCH_X64
1405