LCOV - code coverage report
Current view: top level - src/regexp/x64 - regexp-macro-assembler-x64.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 573 584 98.1 %
Date: 2019-01-20 Functions: 60 62 96.8 %

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

Generated by: LCOV version 1.10