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