• 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/heap/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  *              int num_capture_registers,
89  *              byte* stack_area_base,
90  *              bool direct_call = false,
91  *              Isolate* isolate);
92  */
93 
94 #define __ ACCESS_MASM((&masm_))
95 
RegExpMacroAssemblerX64(Isolate * isolate,Zone * zone,Mode mode,int registers_to_save)96 RegExpMacroAssemblerX64::RegExpMacroAssemblerX64(Isolate* isolate, Zone* zone,
97                                                  Mode mode,
98                                                  int registers_to_save)
99     : NativeRegExpMacroAssembler(isolate, zone),
100       masm_(isolate, nullptr, kRegExpCodeSize, CodeObjectRequired::kYes),
101       no_root_array_scope_(&masm_),
102       code_relative_fixup_positions_(zone),
103       mode_(mode),
104       num_registers_(registers_to_save),
105       num_saved_registers_(registers_to_save),
106       entry_label_(),
107       start_label_(),
108       success_label_(),
109       backtrack_label_(),
110       exit_label_() {
111   DCHECK_EQ(0, registers_to_save % 2);
112   __ jmp(&entry_label_);   // We'll write the entry code when we know more.
113   __ bind(&start_label_);  // And then continue from here.
114 }
115 
116 
~RegExpMacroAssemblerX64()117 RegExpMacroAssemblerX64::~RegExpMacroAssemblerX64() {
118   // Unuse labels in case we throw away the assembler without calling GetCode.
119   entry_label_.Unuse();
120   start_label_.Unuse();
121   success_label_.Unuse();
122   backtrack_label_.Unuse();
123   exit_label_.Unuse();
124   check_preempt_label_.Unuse();
125   stack_overflow_label_.Unuse();
126 }
127 
128 
stack_limit_slack()129 int RegExpMacroAssemblerX64::stack_limit_slack()  {
130   return RegExpStack::kStackLimitSlack;
131 }
132 
133 
AdvanceCurrentPosition(int by)134 void RegExpMacroAssemblerX64::AdvanceCurrentPosition(int by) {
135   if (by != 0) {
136     __ addq(rdi, Immediate(by * char_size()));
137   }
138 }
139 
140 
AdvanceRegister(int reg,int by)141 void RegExpMacroAssemblerX64::AdvanceRegister(int reg, int by) {
142   DCHECK_LE(0, reg);
143   DCHECK_GT(num_registers_, reg);
144   if (by != 0) {
145     __ addp(register_location(reg), Immediate(by));
146   }
147 }
148 
149 
Backtrack()150 void RegExpMacroAssemblerX64::Backtrack() {
151   CheckPreemption();
152   // Pop Code* offset from backtrack stack, add Code* and jump to location.
153   Pop(rbx);
154   __ addp(rbx, code_object_pointer());
155   __ jmp(rbx);
156 }
157 
158 
Bind(Label * label)159 void RegExpMacroAssemblerX64::Bind(Label* label) {
160   __ bind(label);
161 }
162 
163 
CheckCharacter(uint32_t c,Label * on_equal)164 void RegExpMacroAssemblerX64::CheckCharacter(uint32_t c, Label* on_equal) {
165   __ cmpl(current_character(), Immediate(c));
166   BranchOrBacktrack(equal, on_equal);
167 }
168 
169 
CheckCharacterGT(uc16 limit,Label * on_greater)170 void RegExpMacroAssemblerX64::CheckCharacterGT(uc16 limit, Label* on_greater) {
171   __ cmpl(current_character(), Immediate(limit));
172   BranchOrBacktrack(greater, on_greater);
173 }
174 
175 
CheckAtStart(Label * on_at_start)176 void RegExpMacroAssemblerX64::CheckAtStart(Label* on_at_start) {
177   __ leap(rax, Operand(rdi, -char_size()));
178   __ cmpp(rax, Operand(rbp, kStringStartMinusOne));
179   BranchOrBacktrack(equal, on_at_start);
180 }
181 
182 
CheckNotAtStart(int cp_offset,Label * on_not_at_start)183 void RegExpMacroAssemblerX64::CheckNotAtStart(int cp_offset,
184                                               Label* on_not_at_start) {
185   __ leap(rax, Operand(rdi, -char_size() + cp_offset * char_size()));
186   __ cmpp(rax, Operand(rbp, kStringStartMinusOne));
187   BranchOrBacktrack(not_equal, on_not_at_start);
188 }
189 
190 
CheckCharacterLT(uc16 limit,Label * on_less)191 void RegExpMacroAssemblerX64::CheckCharacterLT(uc16 limit, Label* on_less) {
192   __ cmpl(current_character(), Immediate(limit));
193   BranchOrBacktrack(less, on_less);
194 }
195 
196 
CheckGreedyLoop(Label * on_equal)197 void RegExpMacroAssemblerX64::CheckGreedyLoop(Label* on_equal) {
198   Label fallthrough;
199   __ cmpl(rdi, Operand(backtrack_stackpointer(), 0));
200   __ j(not_equal, &fallthrough);
201   Drop();
202   BranchOrBacktrack(no_condition, on_equal);
203   __ bind(&fallthrough);
204 }
205 
206 
CheckNotBackReferenceIgnoreCase(int start_reg,bool read_backward,bool unicode,Label * on_no_match)207 void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
208     int start_reg, bool read_backward, bool unicode, Label* on_no_match) {
209   Label fallthrough;
210   ReadPositionFromRegister(rdx, start_reg);  // Offset of start of capture
211   ReadPositionFromRegister(rbx, start_reg + 1);  // Offset of end of capture
212   __ subp(rbx, rdx);  // Length of capture.
213 
214   // -----------------------
215   // rdx  = Start offset of capture.
216   // rbx = Length of capture
217 
218   // At this point, the capture registers are either both set or both cleared.
219   // If the capture length is zero, then the capture is either empty or cleared.
220   // Fall through in both cases.
221   __ j(equal, &fallthrough);
222 
223   // -----------------------
224   // rdx - Start of capture
225   // rbx - length of capture
226   // Check that there are sufficient characters left in the input.
227   if (read_backward) {
228     __ movl(rax, Operand(rbp, kStringStartMinusOne));
229     __ addl(rax, rbx);
230     __ cmpl(rdi, rax);
231     BranchOrBacktrack(less_equal, on_no_match);
232   } else {
233     __ movl(rax, rdi);
234     __ addl(rax, rbx);
235     BranchOrBacktrack(greater, on_no_match);
236   }
237 
238   if (mode_ == LATIN1) {
239     Label loop_increment;
240     if (on_no_match == nullptr) {
241       on_no_match = &backtrack_label_;
242     }
243 
244     __ leap(r9, Operand(rsi, rdx, times_1, 0));
245     __ leap(r11, Operand(rsi, rdi, times_1, 0));
246     if (read_backward) {
247       __ subp(r11, rbx);  // Offset by length when matching backwards.
248     }
249     __ addp(rbx, r9);  // End of capture
250     // ---------------------
251     // r11 - current input character address
252     // r9 - current capture character address
253     // rbx - end of capture
254 
255     Label loop;
256     __ bind(&loop);
257     __ movzxbl(rdx, Operand(r9, 0));
258     __ movzxbl(rax, Operand(r11, 0));
259     // al - input character
260     // dl - capture character
261     __ cmpb(rax, rdx);
262     __ j(equal, &loop_increment);
263 
264     // Mismatch, try case-insensitive match (converting letters to lower-case).
265     // I.e., if or-ing with 0x20 makes values equal and in range 'a'-'z', it's
266     // a match.
267     __ orp(rax, Immediate(0x20));  // Convert match character to lower-case.
268     __ orp(rdx, Immediate(0x20));  // Convert capture character to lower-case.
269     __ cmpb(rax, rdx);
270     __ j(not_equal, on_no_match);  // Definitely not equal.
271     __ subb(rax, Immediate('a'));
272     __ cmpb(rax, Immediate('z' - 'a'));
273     __ j(below_equal, &loop_increment);  // In range 'a'-'z'.
274     // Latin-1: Check for values in range [224,254] but not 247.
275     __ subb(rax, Immediate(224 - 'a'));
276     __ cmpb(rax, Immediate(254 - 224));
277     __ j(above, on_no_match);  // Weren't Latin-1 letters.
278     __ cmpb(rax, Immediate(247 - 224));  // Check for 247.
279     __ j(equal, on_no_match);
280     __ bind(&loop_increment);
281     // Increment pointers into match and capture strings.
282     __ addp(r11, Immediate(1));
283     __ addp(r9, Immediate(1));
284     // Compare to end of capture, and loop if not done.
285     __ cmpp(r9, rbx);
286     __ j(below, &loop);
287 
288     // Compute new value of character position after the matched part.
289     __ movp(rdi, r11);
290     __ subq(rdi, rsi);
291     if (read_backward) {
292       // Subtract match length if we matched backward.
293       __ addq(rdi, register_location(start_reg));
294       __ subq(rdi, register_location(start_reg + 1));
295     }
296   } else {
297     DCHECK(mode_ == UC16);
298     // Save important/volatile registers before calling C function.
299 #ifndef _WIN64
300     // Caller save on Linux and callee save in Windows.
301     __ pushq(rsi);
302     __ pushq(rdi);
303 #endif
304     __ pushq(backtrack_stackpointer());
305 
306     static const int num_arguments = 4;
307     __ PrepareCallCFunction(num_arguments);
308 
309     // Put arguments into parameter registers. Parameters are
310     //   Address byte_offset1 - Address captured substring's start.
311     //   Address byte_offset2 - Address of current character position.
312     //   size_t byte_length - length of capture in bytes(!)
313 //   Isolate* isolate or 0 if unicode flag.
314 #ifdef _WIN64
315     DCHECK(rcx == arg_reg_1);
316     DCHECK(rdx == arg_reg_2);
317     // Compute and set byte_offset1 (start of capture).
318     __ leap(rcx, Operand(rsi, rdx, times_1, 0));
319     // Set byte_offset2.
320     __ leap(rdx, Operand(rsi, rdi, times_1, 0));
321     if (read_backward) {
322       __ subq(rdx, rbx);
323     }
324 #else  // AMD64 calling convention
325     DCHECK(rdi == arg_reg_1);
326     DCHECK(rsi == arg_reg_2);
327     // Compute byte_offset2 (current position = rsi+rdi).
328     __ leap(rax, Operand(rsi, rdi, times_1, 0));
329     // Compute and set byte_offset1 (start of capture).
330     __ leap(rdi, Operand(rsi, rdx, times_1, 0));
331     // Set byte_offset2.
332     __ movp(rsi, rax);
333     if (read_backward) {
334       __ subq(rsi, rbx);
335     }
336 #endif  // _WIN64
337 
338     // Set byte_length.
339     __ movp(arg_reg_3, rbx);
340     // Isolate.
341 #ifdef V8_INTL_SUPPORT
342     if (unicode) {
343       __ movp(arg_reg_4, Immediate(0));
344     } else  // NOLINT
345 #endif      // V8_INTL_SUPPORT
346     {
347       __ LoadAddress(arg_reg_4, ExternalReference::isolate_address(isolate()));
348     }
349 
350     { // NOLINT: Can't find a way to open this scope without confusing the
351       // linter.
352       AllowExternalCallThatCantCauseGC scope(&masm_);
353       ExternalReference compare =
354           ExternalReference::re_case_insensitive_compare_uc16(isolate());
355       __ CallCFunction(compare, num_arguments);
356     }
357 
358     // Restore original values before reacting on result value.
359     __ Move(code_object_pointer(), masm_.CodeObject());
360     __ popq(backtrack_stackpointer());
361 #ifndef _WIN64
362     __ popq(rdi);
363     __ popq(rsi);
364 #endif
365 
366     // Check if function returned non-zero for success or zero for failure.
367     __ testp(rax, rax);
368     BranchOrBacktrack(zero, on_no_match);
369     // On success, advance position by length of capture.
370     // Requires that rbx is callee save (true for both Win64 and AMD64 ABIs).
371     if (read_backward) {
372       __ subq(rdi, rbx);
373     } else {
374       __ addq(rdi, rbx);
375     }
376   }
377   __ bind(&fallthrough);
378 }
379 
380 
CheckNotBackReference(int start_reg,bool read_backward,Label * on_no_match)381 void RegExpMacroAssemblerX64::CheckNotBackReference(int start_reg,
382                                                     bool read_backward,
383                                                     Label* on_no_match) {
384   Label fallthrough;
385 
386   // Find length of back-referenced capture.
387   ReadPositionFromRegister(rdx, start_reg);  // Offset of start of capture
388   ReadPositionFromRegister(rax, start_reg + 1);  // Offset of end of capture
389   __ subp(rax, rdx);  // Length to check.
390 
391   // At this point, the capture registers are either both set or both cleared.
392   // If the capture length is zero, then the capture is either empty or cleared.
393   // Fall through in both cases.
394   __ j(equal, &fallthrough);
395 
396   // -----------------------
397   // rdx - Start of capture
398   // rax - length of capture
399   // Check that there are sufficient characters left in the input.
400   if (read_backward) {
401     __ movl(rbx, Operand(rbp, kStringStartMinusOne));
402     __ addl(rbx, rax);
403     __ cmpl(rdi, rbx);
404     BranchOrBacktrack(less_equal, on_no_match);
405   } else {
406     __ movl(rbx, rdi);
407     __ addl(rbx, rax);
408     BranchOrBacktrack(greater, on_no_match);
409   }
410 
411   // Compute pointers to match string and capture string
412   __ leap(rbx, Operand(rsi, rdi, times_1, 0));  // Start of match.
413   if (read_backward) {
414     __ subq(rbx, rax);  // Offset by length when matching backwards.
415   }
416   __ addp(rdx, rsi);  // Start of capture.
417   __ leap(r9, Operand(rdx, rax, times_1, 0));  // End of capture
418 
419   // -----------------------
420   // rbx - current capture character address.
421   // rbx - current input character address .
422   // r9 - end of input to match (capture length after rbx).
423 
424   Label loop;
425   __ bind(&loop);
426   if (mode_ == LATIN1) {
427     __ movzxbl(rax, Operand(rdx, 0));
428     __ cmpb(rax, Operand(rbx, 0));
429   } else {
430     DCHECK(mode_ == UC16);
431     __ movzxwl(rax, Operand(rdx, 0));
432     __ cmpw(rax, Operand(rbx, 0));
433   }
434   BranchOrBacktrack(not_equal, on_no_match);
435   // Increment pointers into capture and match string.
436   __ addp(rbx, Immediate(char_size()));
437   __ addp(rdx, Immediate(char_size()));
438   // Check if we have reached end of match area.
439   __ cmpp(rdx, r9);
440   __ j(below, &loop);
441 
442   // Success.
443   // Set current character position to position after match.
444   __ movp(rdi, rbx);
445   __ subq(rdi, rsi);
446   if (read_backward) {
447     // Subtract match length if we matched backward.
448     __ addq(rdi, register_location(start_reg));
449     __ subq(rdi, register_location(start_reg + 1));
450   }
451 
452   __ bind(&fallthrough);
453 }
454 
455 
CheckNotCharacter(uint32_t c,Label * on_not_equal)456 void RegExpMacroAssemblerX64::CheckNotCharacter(uint32_t c,
457                                                 Label* on_not_equal) {
458   __ cmpl(current_character(), Immediate(c));
459   BranchOrBacktrack(not_equal, on_not_equal);
460 }
461 
462 
CheckCharacterAfterAnd(uint32_t c,uint32_t mask,Label * on_equal)463 void RegExpMacroAssemblerX64::CheckCharacterAfterAnd(uint32_t c,
464                                                      uint32_t mask,
465                                                      Label* on_equal) {
466   if (c == 0) {
467     __ testl(current_character(), Immediate(mask));
468   } else {
469     __ movl(rax, Immediate(mask));
470     __ andp(rax, current_character());
471     __ cmpl(rax, Immediate(c));
472   }
473   BranchOrBacktrack(equal, on_equal);
474 }
475 
476 
CheckNotCharacterAfterAnd(uint32_t c,uint32_t mask,Label * on_not_equal)477 void RegExpMacroAssemblerX64::CheckNotCharacterAfterAnd(uint32_t c,
478                                                         uint32_t mask,
479                                                         Label* on_not_equal) {
480   if (c == 0) {
481     __ testl(current_character(), Immediate(mask));
482   } else {
483     __ movl(rax, Immediate(mask));
484     __ andp(rax, current_character());
485     __ cmpl(rax, Immediate(c));
486   }
487   BranchOrBacktrack(not_equal, on_not_equal);
488 }
489 
490 
CheckNotCharacterAfterMinusAnd(uc16 c,uc16 minus,uc16 mask,Label * on_not_equal)491 void RegExpMacroAssemblerX64::CheckNotCharacterAfterMinusAnd(
492     uc16 c,
493     uc16 minus,
494     uc16 mask,
495     Label* on_not_equal) {
496   DCHECK_GT(String::kMaxUtf16CodeUnit, minus);
497   __ leap(rax, Operand(current_character(), -minus));
498   __ andp(rax, Immediate(mask));
499   __ cmpl(rax, Immediate(c));
500   BranchOrBacktrack(not_equal, on_not_equal);
501 }
502 
503 
CheckCharacterInRange(uc16 from,uc16 to,Label * on_in_range)504 void RegExpMacroAssemblerX64::CheckCharacterInRange(
505     uc16 from,
506     uc16 to,
507     Label* on_in_range) {
508   __ leal(rax, Operand(current_character(), -from));
509   __ cmpl(rax, Immediate(to - from));
510   BranchOrBacktrack(below_equal, on_in_range);
511 }
512 
513 
CheckCharacterNotInRange(uc16 from,uc16 to,Label * on_not_in_range)514 void RegExpMacroAssemblerX64::CheckCharacterNotInRange(
515     uc16 from,
516     uc16 to,
517     Label* on_not_in_range) {
518   __ leal(rax, Operand(current_character(), -from));
519   __ cmpl(rax, Immediate(to - from));
520   BranchOrBacktrack(above, on_not_in_range);
521 }
522 
523 
CheckBitInTable(Handle<ByteArray> table,Label * on_bit_set)524 void RegExpMacroAssemblerX64::CheckBitInTable(
525     Handle<ByteArray> table,
526     Label* on_bit_set) {
527   __ Move(rax, table);
528   Register index = current_character();
529   if (mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) {
530     __ movp(rbx, current_character());
531     __ andp(rbx, Immediate(kTableMask));
532     index = rbx;
533   }
534   __ cmpb(FieldOperand(rax, index, times_1, ByteArray::kHeaderSize),
535           Immediate(0));
536   BranchOrBacktrack(not_equal, on_bit_set);
537 }
538 
539 
CheckSpecialCharacterClass(uc16 type,Label * on_no_match)540 bool RegExpMacroAssemblerX64::CheckSpecialCharacterClass(uc16 type,
541                                                          Label* on_no_match) {
542   // Range checks (c in min..max) are generally implemented by an unsigned
543   // (c - min) <= (max - min) check, using the sequence:
544   //   leap(rax, Operand(current_character(), -min)) or sub(rax, Immediate(min))
545   //   cmp(rax, Immediate(max - min))
546   switch (type) {
547   case 's':
548     // Match space-characters
549     if (mode_ == LATIN1) {
550       // One byte space characters are '\t'..'\r', ' ' and \u00a0.
551       Label success;
552       __ cmpl(current_character(), Immediate(' '));
553       __ j(equal, &success, Label::kNear);
554       // Check range 0x09..0x0D
555       __ leap(rax, Operand(current_character(), -'\t'));
556       __ cmpl(rax, Immediate('\r' - '\t'));
557       __ j(below_equal, &success, Label::kNear);
558       // \u00a0 (NBSP).
559       __ cmpl(rax, Immediate(0x00A0 - '\t'));
560       BranchOrBacktrack(not_equal, on_no_match);
561       __ bind(&success);
562       return true;
563     }
564     return false;
565   case 'S':
566     // The emitted code for generic character classes is good enough.
567     return false;
568   case 'd':
569     // Match ASCII digits ('0'..'9')
570     __ leap(rax, Operand(current_character(), -'0'));
571     __ cmpl(rax, Immediate('9' - '0'));
572     BranchOrBacktrack(above, on_no_match);
573     return true;
574   case 'D':
575     // Match non ASCII-digits
576     __ leap(rax, Operand(current_character(), -'0'));
577     __ cmpl(rax, Immediate('9' - '0'));
578     BranchOrBacktrack(below_equal, on_no_match);
579     return true;
580   case '.': {
581     // Match non-newlines (not 0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029)
582     __ movl(rax, current_character());
583     __ xorp(rax, Immediate(0x01));
584     // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C
585     __ subl(rax, Immediate(0x0B));
586     __ cmpl(rax, Immediate(0x0C - 0x0B));
587     BranchOrBacktrack(below_equal, on_no_match);
588     if (mode_ == UC16) {
589       // Compare original value to 0x2028 and 0x2029, using the already
590       // computed (current_char ^ 0x01 - 0x0B). I.e., check for
591       // 0x201D (0x2028 - 0x0B) or 0x201E.
592       __ subl(rax, Immediate(0x2028 - 0x0B));
593       __ cmpl(rax, Immediate(0x2029 - 0x2028));
594       BranchOrBacktrack(below_equal, on_no_match);
595     }
596     return true;
597   }
598   case 'n': {
599     // Match newlines (0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029)
600     __ movl(rax, current_character());
601     __ xorp(rax, Immediate(0x01));
602     // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C
603     __ subl(rax, Immediate(0x0B));
604     __ cmpl(rax, Immediate(0x0C - 0x0B));
605     if (mode_ == LATIN1) {
606       BranchOrBacktrack(above, on_no_match);
607     } else {
608       Label done;
609       BranchOrBacktrack(below_equal, &done);
610       // Compare original value to 0x2028 and 0x2029, using the already
611       // computed (current_char ^ 0x01 - 0x0B). I.e., check for
612       // 0x201D (0x2028 - 0x0B) or 0x201E.
613       __ subl(rax, Immediate(0x2028 - 0x0B));
614       __ cmpl(rax, Immediate(0x2029 - 0x2028));
615       BranchOrBacktrack(above, on_no_match);
616       __ bind(&done);
617     }
618     return true;
619   }
620   case 'w': {
621     if (mode_ != LATIN1) {
622       // Table is 256 entries, so all Latin1 characters can be tested.
623       __ cmpl(current_character(), Immediate('z'));
624       BranchOrBacktrack(above, on_no_match);
625     }
626     __ Move(rbx, ExternalReference::re_word_character_map(isolate()));
627     DCHECK_EQ(0, word_character_map[0]);  // Character '\0' is not a word char.
628     __ testb(Operand(rbx, current_character(), times_1, 0),
629              current_character());
630     BranchOrBacktrack(zero, on_no_match);
631     return true;
632   }
633   case 'W': {
634     Label done;
635     if (mode_ != LATIN1) {
636       // Table is 256 entries, so all Latin1 characters can be tested.
637       __ cmpl(current_character(), Immediate('z'));
638       __ j(above, &done);
639     }
640     __ Move(rbx, ExternalReference::re_word_character_map(isolate()));
641     DCHECK_EQ(0, word_character_map[0]);  // Character '\0' is not a word char.
642     __ testb(Operand(rbx, current_character(), times_1, 0),
643              current_character());
644     BranchOrBacktrack(not_zero, on_no_match);
645     if (mode_ != LATIN1) {
646       __ bind(&done);
647     }
648     return true;
649   }
650 
651   case '*':
652     // Match any character.
653     return true;
654   // No custom implementation (yet): s(UC16), S(UC16).
655   default:
656     return false;
657   }
658 }
659 
660 
Fail()661 void RegExpMacroAssemblerX64::Fail() {
662   STATIC_ASSERT(FAILURE == 0);  // Return value for failure is zero.
663   if (!global()) {
664     __ Set(rax, FAILURE);
665   }
666   __ jmp(&exit_label_);
667 }
668 
669 
GetCode(Handle<String> source)670 Handle<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
671   Label return_rax;
672   // Finalize code - write the entry point code now we know how many
673   // registers we need.
674   // Entry code:
675   __ bind(&entry_label_);
676 
677   // Tell the system that we have a stack frame.  Because the type is MANUAL, no
678   // is generated.
679   FrameScope scope(&masm_, StackFrame::MANUAL);
680 
681   // Actually emit code to start a new stack frame.
682   __ pushq(rbp);
683   __ movp(rbp, rsp);
684   // Save parameters and callee-save registers. Order here should correspond
685   //  to order of kBackup_ebx etc.
686 #ifdef _WIN64
687   // MSVC passes arguments in rcx, rdx, r8, r9, with backing stack slots.
688   // Store register parameters in pre-allocated stack slots,
689   __ movq(Operand(rbp, kInputString), rcx);
690   __ movq(Operand(rbp, kStartIndex), rdx);  // Passed as int32 in edx.
691   __ movq(Operand(rbp, kInputStart), r8);
692   __ movq(Operand(rbp, kInputEnd), r9);
693   // Callee-save on Win64.
694   __ pushq(rsi);
695   __ pushq(rdi);
696   __ pushq(rbx);
697 #else
698   // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9 (and then on stack).
699   // Push register parameters on stack for reference.
700   DCHECK_EQ(kInputString, -1 * kRegisterSize);
701   DCHECK_EQ(kStartIndex, -2 * kRegisterSize);
702   DCHECK_EQ(kInputStart, -3 * kRegisterSize);
703   DCHECK_EQ(kInputEnd, -4 * kRegisterSize);
704   DCHECK_EQ(kRegisterOutput, -5 * kRegisterSize);
705   DCHECK_EQ(kNumOutputRegisters, -6 * kRegisterSize);
706   __ pushq(rdi);
707   __ pushq(rsi);
708   __ pushq(rdx);
709   __ pushq(rcx);
710   __ pushq(r8);
711   __ pushq(r9);
712 
713   __ pushq(rbx);  // Callee-save
714 #endif
715 
716   __ Push(Immediate(0));  // Number of successful matches in a global regexp.
717   __ Push(Immediate(0));  // Make room for "string start - 1" constant.
718 
719   // Check if we have space on the stack for registers.
720   Label stack_limit_hit;
721   Label stack_ok;
722 
723   ExternalReference stack_limit =
724       ExternalReference::address_of_stack_limit(isolate());
725   __ movp(rcx, rsp);
726   __ Move(kScratchRegister, stack_limit);
727   __ subp(rcx, Operand(kScratchRegister, 0));
728   // Handle it if the stack pointer is already below the stack limit.
729   __ j(below_equal, &stack_limit_hit);
730   // Check if there is room for the variable number of registers above
731   // the stack limit.
732   __ cmpp(rcx, Immediate(num_registers_ * kPointerSize));
733   __ j(above_equal, &stack_ok);
734   // Exit with OutOfMemory exception. There is not enough space on the stack
735   // for our working registers.
736   __ Set(rax, EXCEPTION);
737   __ jmp(&return_rax);
738 
739   __ bind(&stack_limit_hit);
740   __ Move(code_object_pointer(), masm_.CodeObject());
741   CallCheckStackGuardState();  // Preserves no registers beside rbp and rsp.
742   __ testp(rax, rax);
743   // If returned value is non-zero, we exit with the returned value as result.
744   __ j(not_zero, &return_rax);
745 
746   __ bind(&stack_ok);
747 
748   // Allocate space on stack for registers.
749   __ subp(rsp, Immediate(num_registers_ * kPointerSize));
750   // Load string length.
751   __ movp(rsi, Operand(rbp, kInputEnd));
752   // Load input position.
753   __ movp(rdi, Operand(rbp, kInputStart));
754   // Set up rdi to be negative offset from string end.
755   __ subq(rdi, rsi);
756   // Set rax to address of char before start of the string
757   // (effectively string position -1).
758   __ movp(rbx, Operand(rbp, kStartIndex));
759   __ negq(rbx);
760   if (mode_ == UC16) {
761     __ leap(rax, Operand(rdi, rbx, times_2, -char_size()));
762   } else {
763     __ leap(rax, Operand(rdi, rbx, times_1, -char_size()));
764   }
765   // Store this value in a local variable, for use when clearing
766   // position registers.
767   __ movp(Operand(rbp, kStringStartMinusOne), rax);
768 
769 #if V8_OS_WIN
770   // Ensure that we have written to each stack page, in order. Skipping a page
771   // on Windows can cause segmentation faults. Assuming page size is 4k.
772   const int kPageSize = 4096;
773   const int kRegistersPerPage = kPageSize / kPointerSize;
774   for (int i = num_saved_registers_ + kRegistersPerPage - 1;
775       i < num_registers_;
776       i += kRegistersPerPage) {
777     __ movp(register_location(i), rax);  // One write every page.
778   }
779 #endif  // V8_OS_WIN
780 
781   // Initialize code object pointer.
782   __ Move(code_object_pointer(), masm_.CodeObject());
783 
784   Label load_char_start_regexp, start_regexp;
785   // Load newline if index is at start, previous character otherwise.
786   __ cmpl(Operand(rbp, kStartIndex), Immediate(0));
787   __ j(not_equal, &load_char_start_regexp, Label::kNear);
788   __ Set(current_character(), '\n');
789   __ jmp(&start_regexp, Label::kNear);
790 
791   // Global regexp restarts matching here.
792   __ bind(&load_char_start_regexp);
793   // Load previous char as initial value of current character register.
794   LoadCurrentCharacterUnchecked(-1, 1);
795   __ bind(&start_regexp);
796 
797   // Initialize on-stack registers.
798   if (num_saved_registers_ > 0) {
799     // Fill saved registers with initial value = start offset - 1
800     // Fill in stack push order, to avoid accessing across an unwritten
801     // page (a problem on Windows).
802     if (num_saved_registers_ > 8) {
803       __ Set(rcx, kRegisterZero);
804       Label init_loop;
805       __ bind(&init_loop);
806       __ movp(Operand(rbp, rcx, times_1, 0), rax);
807       __ subq(rcx, Immediate(kPointerSize));
808       __ cmpq(rcx,
809               Immediate(kRegisterZero - num_saved_registers_ * kPointerSize));
810       __ j(greater, &init_loop);
811     } else {  // Unroll the loop.
812       for (int i = 0; i < num_saved_registers_; i++) {
813         __ movp(register_location(i), rax);
814       }
815     }
816   }
817 
818   // Initialize backtrack stack pointer.
819   __ movp(backtrack_stackpointer(), Operand(rbp, kStackHighEnd));
820 
821   __ jmp(&start_label_);
822 
823   // Exit code:
824   if (success_label_.is_linked()) {
825     // Save captures when successful.
826     __ bind(&success_label_);
827     if (num_saved_registers_ > 0) {
828       // copy captures to output
829       __ movp(rdx, Operand(rbp, kStartIndex));
830       __ movp(rbx, Operand(rbp, kRegisterOutput));
831       __ movp(rcx, Operand(rbp, kInputEnd));
832       __ subp(rcx, Operand(rbp, kInputStart));
833       if (mode_ == UC16) {
834         __ leap(rcx, Operand(rcx, rdx, times_2, 0));
835       } else {
836         __ addp(rcx, rdx);
837       }
838       for (int i = 0; i < num_saved_registers_; i++) {
839         __ movp(rax, register_location(i));
840         if (i == 0 && global_with_zero_length_check()) {
841           // Keep capture start in rdx for the zero-length check later.
842           __ movp(rdx, rax);
843         }
844         __ addp(rax, rcx);  // Convert to index from start, not end.
845         if (mode_ == UC16) {
846           __ sarp(rax, Immediate(1));  // Convert byte index to character index.
847         }
848         __ movl(Operand(rbx, i * kIntSize), rax);
849       }
850     }
851 
852     if (global()) {
853       // Restart matching if the regular expression is flagged as global.
854       // Increment success counter.
855       __ incp(Operand(rbp, kSuccessfulCaptures));
856       // Capture results have been stored, so the number of remaining global
857       // output registers is reduced by the number of stored captures.
858       __ movsxlq(rcx, Operand(rbp, kNumOutputRegisters));
859       __ subp(rcx, Immediate(num_saved_registers_));
860       // Check whether we have enough room for another set of capture results.
861       __ cmpp(rcx, Immediate(num_saved_registers_));
862       __ j(less, &exit_label_);
863 
864       __ movp(Operand(rbp, kNumOutputRegisters), rcx);
865       // Advance the location for output.
866       __ addp(Operand(rbp, kRegisterOutput),
867               Immediate(num_saved_registers_ * kIntSize));
868 
869       // Prepare rax to initialize registers with its value in the next run.
870       __ movp(rax, Operand(rbp, kStringStartMinusOne));
871 
872       if (global_with_zero_length_check()) {
873         // Special case for zero-length matches.
874         // rdx: capture start index
875         __ cmpp(rdi, rdx);
876         // Not a zero-length match, restart.
877         __ j(not_equal, &load_char_start_regexp);
878         // rdi (offset from the end) is zero if we already reached the end.
879         __ testp(rdi, rdi);
880         __ j(zero, &exit_label_, Label::kNear);
881         // Advance current position after a zero-length match.
882         Label advance;
883         __ bind(&advance);
884         if (mode_ == UC16) {
885           __ addq(rdi, Immediate(2));
886         } else {
887           __ incq(rdi);
888         }
889         if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
890       }
891 
892       __ jmp(&load_char_start_regexp);
893     } else {
894       __ movp(rax, Immediate(SUCCESS));
895     }
896   }
897 
898   __ bind(&exit_label_);
899   if (global()) {
900     // Return the number of successful captures.
901     __ movp(rax, Operand(rbp, kSuccessfulCaptures));
902   }
903 
904   __ bind(&return_rax);
905 #ifdef _WIN64
906   // Restore callee save registers.
907   __ leap(rsp, Operand(rbp, kLastCalleeSaveRegister));
908   __ popq(rbx);
909   __ popq(rdi);
910   __ popq(rsi);
911   // Stack now at rbp.
912 #else
913   // Restore callee save register.
914   __ movp(rbx, Operand(rbp, kBackup_rbx));
915   // Skip rsp to rbp.
916   __ movp(rsp, rbp);
917 #endif
918   // Exit function frame, restore previous one.
919   __ popq(rbp);
920   __ ret(0);
921 
922   // Backtrack code (branch target for conditional backtracks).
923   if (backtrack_label_.is_linked()) {
924     __ bind(&backtrack_label_);
925     Backtrack();
926   }
927 
928   Label exit_with_exception;
929 
930   // Preempt-code
931   if (check_preempt_label_.is_linked()) {
932     SafeCallTarget(&check_preempt_label_);
933 
934     __ pushq(backtrack_stackpointer());
935     __ pushq(rdi);
936 
937     CallCheckStackGuardState();
938     __ testp(rax, rax);
939     // If returning non-zero, we should end execution with the given
940     // result as return value.
941     __ j(not_zero, &return_rax);
942 
943     // Restore registers.
944     __ Move(code_object_pointer(), masm_.CodeObject());
945     __ popq(rdi);
946     __ popq(backtrack_stackpointer());
947     // String might have moved: Reload esi from frame.
948     __ movp(rsi, Operand(rbp, kInputEnd));
949     SafeReturn();
950   }
951 
952   // Backtrack stack overflow code.
953   if (stack_overflow_label_.is_linked()) {
954     SafeCallTarget(&stack_overflow_label_);
955     // Reached if the backtrack-stack limit has been hit.
956 
957     Label grow_failed;
958     // Save registers before calling C function
959 #ifndef _WIN64
960     // Callee-save in Microsoft 64-bit ABI, but not in AMD64 ABI.
961     __ pushq(rsi);
962     __ pushq(rdi);
963 #endif
964 
965     // Call GrowStack(backtrack_stackpointer())
966     static const int num_arguments = 3;
967     __ PrepareCallCFunction(num_arguments);
968 #ifdef _WIN64
969     // Microsoft passes parameters in rcx, rdx, r8.
970     // First argument, backtrack stackpointer, is already in rcx.
971     __ leap(rdx, Operand(rbp, kStackHighEnd));  // Second argument
972     __ LoadAddress(r8, ExternalReference::isolate_address(isolate()));
973 #else
974     // AMD64 ABI passes parameters in rdi, rsi, rdx.
975     __ movp(rdi, backtrack_stackpointer());   // First argument.
976     __ leap(rsi, Operand(rbp, kStackHighEnd));  // Second argument.
977     __ LoadAddress(rdx, ExternalReference::isolate_address(isolate()));
978 #endif
979     ExternalReference grow_stack =
980         ExternalReference::re_grow_stack(isolate());
981     __ CallCFunction(grow_stack, num_arguments);
982     // If return nullptr, we have failed to grow the stack, and
983     // must exit with a stack-overflow exception.
984     __ testp(rax, rax);
985     __ j(equal, &exit_with_exception);
986     // Otherwise use return value as new stack pointer.
987     __ movp(backtrack_stackpointer(), rax);
988     // Restore saved registers and continue.
989     __ Move(code_object_pointer(), masm_.CodeObject());
990 #ifndef _WIN64
991     __ popq(rdi);
992     __ popq(rsi);
993 #endif
994     SafeReturn();
995   }
996 
997   if (exit_with_exception.is_linked()) {
998     // If any of the code above needed to exit with an exception.
999     __ bind(&exit_with_exception);
1000     // Exit with Result EXCEPTION(-1) to signal thrown exception.
1001     __ Set(rax, EXCEPTION);
1002     __ jmp(&return_rax);
1003   }
1004 
1005   FixupCodeRelativePositions();
1006 
1007   CodeDesc code_desc;
1008   Isolate* isolate = this->isolate();
1009   masm_.GetCode(isolate, &code_desc);
1010   Handle<Code> code =
1011       isolate->factory()->NewCode(code_desc, Code::REGEXP, 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_t>(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 == nullptr) {
1260       Backtrack();
1261       return;
1262     }
1263     __ jmp(to);
1264     return;
1265   }
1266   if (to == nullptr) {
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 != 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 position : code_relative_fixup_positions_) {
1308     // The position succeeds a relative label offset from position.
1309     // Patch the relative offset to be relative to the Code object pointer
1310     // instead.
1311     int patch_position = position - kIntSize;
1312     int offset = masm_.long_at(patch_position);
1313     masm_.long_at_put(patch_position,
1314                        offset
1315                        + position
1316                        + Code::kHeaderSize
1317                        - kHeapObjectTag);
1318   }
1319   code_relative_fixup_positions_.Rewind(0);
1320 }
1321 
1322 
Push(Label * backtrack_target)1323 void RegExpMacroAssemblerX64::Push(Label* backtrack_target) {
1324   __ subp(backtrack_stackpointer(), Immediate(kIntSize));
1325   __ movl(Operand(backtrack_stackpointer(), 0), backtrack_target);
1326   MarkPositionForCodeRelativeFixup();
1327 }
1328 
1329 
Pop(Register target)1330 void RegExpMacroAssemblerX64::Pop(Register target) {
1331   DCHECK(target != backtrack_stackpointer());
1332   __ movsxlq(target, Operand(backtrack_stackpointer(), 0));
1333   // Notice: This updates flags, unlike normal Pop.
1334   __ addp(backtrack_stackpointer(), Immediate(kIntSize));
1335 }
1336 
1337 
Drop()1338 void RegExpMacroAssemblerX64::Drop() {
1339   __ addp(backtrack_stackpointer(), Immediate(kIntSize));
1340 }
1341 
1342 
CheckPreemption()1343 void RegExpMacroAssemblerX64::CheckPreemption() {
1344   // Check for preemption.
1345   Label no_preempt;
1346   ExternalReference stack_limit =
1347       ExternalReference::address_of_stack_limit(isolate());
1348   __ load_rax(stack_limit);
1349   __ cmpp(rsp, rax);
1350   __ j(above, &no_preempt);
1351 
1352   SafeCall(&check_preempt_label_);
1353 
1354   __ bind(&no_preempt);
1355 }
1356 
1357 
CheckStackLimit()1358 void RegExpMacroAssemblerX64::CheckStackLimit() {
1359   Label no_stack_overflow;
1360   ExternalReference stack_limit =
1361       ExternalReference::address_of_regexp_stack_limit(isolate());
1362   __ load_rax(stack_limit);
1363   __ cmpp(backtrack_stackpointer(), rax);
1364   __ j(above, &no_stack_overflow);
1365 
1366   SafeCall(&stack_overflow_label_);
1367 
1368   __ bind(&no_stack_overflow);
1369 }
1370 
1371 
LoadCurrentCharacterUnchecked(int cp_offset,int characters)1372 void RegExpMacroAssemblerX64::LoadCurrentCharacterUnchecked(int cp_offset,
1373                                                             int characters) {
1374   if (mode_ == LATIN1) {
1375     if (characters == 4) {
1376       __ movl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1377     } else if (characters == 2) {
1378       __ movzxwl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1379     } else {
1380       DCHECK_EQ(1, characters);
1381       __ movzxbl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1382     }
1383   } else {
1384     DCHECK(mode_ == UC16);
1385     if (characters == 2) {
1386       __ movl(current_character(),
1387               Operand(rsi, rdi, times_1, cp_offset * sizeof(uc16)));
1388     } else {
1389       DCHECK_EQ(1, characters);
1390       __ movzxwl(current_character(),
1391                  Operand(rsi, rdi, times_1, cp_offset * sizeof(uc16)));
1392     }
1393   }
1394 }
1395 
1396 #undef __
1397 
1398 #endif  // V8_INTERPRETED_REGEXP
1399 
1400 }  // namespace internal
1401 }  // namespace v8
1402 
1403 #endif  // V8_TARGET_ARCH_X64
1404