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: 549 560 98.0 %
Date: 2017-04-26 Functions: 58 60 96.7 %

          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/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       92258 : RegExpMacroAssemblerX64::RegExpMacroAssemblerX64(Isolate* isolate, Zone* zone,
      97             :                                                  Mode mode,
      98             :                                                  int registers_to_save)
      99             :     : NativeRegExpMacroAssembler(isolate, zone),
     100             :       masm_(isolate, NULL, kRegExpCodeSize, CodeObjectRequired::kYes),
     101             :       no_root_array_scope_(&masm_),
     102             :       code_relative_fixup_positions_(4, 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      184516 :       exit_label_() {
     111             :   DCHECK_EQ(0, registers_to_save % 2);
     112       92258 :   __ jmp(&entry_label_);   // We'll write the entry code when we know more.
     113       92258 :   __ bind(&start_label_);  // And then continue from here.
     114       92258 : }
     115             : 
     116             : 
     117      184516 : 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       92258 : }
     127             : 
     128             : 
     129      595306 : int RegExpMacroAssemblerX64::stack_limit_slack()  {
     130      595306 :   return RegExpStack::kStackLimitSlack;
     131             : }
     132             : 
     133             : 
     134     1194884 : void RegExpMacroAssemblerX64::AdvanceCurrentPosition(int by) {
     135      597442 :   if (by != 0) {
     136     1194884 :     __ addq(rdi, Immediate(by * char_size()));
     137             :   }
     138      597442 : }
     139             : 
     140             : 
     141        7319 : void RegExpMacroAssemblerX64::AdvanceRegister(int reg, int by) {
     142             :   DCHECK(reg >= 0);
     143             :   DCHECK(reg < num_registers_);
     144        7319 :   if (by != 0) {
     145        7319 :     __ addp(register_location(reg), Immediate(by));
     146             :   }
     147        7319 : }
     148             : 
     149             : 
     150      238112 : void RegExpMacroAssemblerX64::Backtrack() {
     151      238112 :   CheckPreemption();
     152             :   // Pop Code* offset from backtrack stack, add Code* and jump to location.
     153      238112 :   Pop(rbx);
     154      238112 :   __ addp(rbx, code_object_pointer());
     155      238112 :   __ jmp(rbx);
     156      238112 : }
     157             : 
     158             : 
     159     2879473 : void RegExpMacroAssemblerX64::Bind(Label* label) {
     160     2879473 :   __ bind(label);
     161     2879473 : }
     162             : 
     163             : 
     164      176721 : void RegExpMacroAssemblerX64::CheckCharacter(uint32_t c, Label* on_equal) {
     165      353442 :   __ cmpl(current_character(), Immediate(c));
     166      176721 :   BranchOrBacktrack(equal, on_equal);
     167      176721 : }
     168             : 
     169             : 
     170       22090 : void RegExpMacroAssemblerX64::CheckCharacterGT(uc16 limit, Label* on_greater) {
     171       44180 :   __ cmpl(current_character(), Immediate(limit));
     172       22090 :   BranchOrBacktrack(greater, on_greater);
     173       22090 : }
     174             : 
     175             : 
     176         979 : void RegExpMacroAssemblerX64::CheckAtStart(Label* on_at_start) {
     177        1958 :   __ leap(rax, Operand(rdi, -char_size()));
     178        1958 :   __ cmpp(rax, Operand(rbp, kStringStartMinusOne));
     179         979 :   BranchOrBacktrack(equal, on_at_start);
     180         979 : }
     181             : 
     182             : 
     183        4680 : void RegExpMacroAssemblerX64::CheckNotAtStart(int cp_offset,
     184        4680 :                                               Label* on_not_at_start) {
     185        9360 :   __ leap(rax, Operand(rdi, -char_size() + cp_offset * char_size()));
     186        9360 :   __ cmpp(rax, Operand(rbp, kStringStartMinusOne));
     187        4680 :   BranchOrBacktrack(not_equal, on_not_at_start);
     188        4680 : }
     189             : 
     190             : 
     191       18552 : void RegExpMacroAssemblerX64::CheckCharacterLT(uc16 limit, Label* on_less) {
     192       37104 :   __ cmpl(current_character(), Immediate(limit));
     193       18552 :   BranchOrBacktrack(less, on_less);
     194       18552 : }
     195             : 
     196             : 
     197       16047 : void RegExpMacroAssemblerX64::CheckGreedyLoop(Label* on_equal) {
     198             :   Label fallthrough;
     199       32094 :   __ cmpl(rdi, Operand(backtrack_stackpointer(), 0));
     200       16047 :   __ j(not_equal, &fallthrough);
     201             :   Drop();
     202       16047 :   BranchOrBacktrack(no_condition, on_equal);
     203       16047 :   __ bind(&fallthrough);
     204       16047 : }
     205             : 
     206             : 
     207        2274 : void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
     208             :     int start_reg, bool read_backward, bool unicode, Label* on_no_match) {
     209             :   Label fallthrough;
     210        2274 :   ReadPositionFromRegister(rdx, start_reg);  // Offset of start of capture
     211        2274 :   ReadPositionFromRegister(rbx, start_reg + 1);  // Offset of end of capture
     212        2274 :   __ 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        2274 :   __ 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        2274 :   if (read_backward) {
     228         156 :     __ movl(rax, Operand(rbp, kStringStartMinusOne));
     229          78 :     __ addl(rax, rbx);
     230          78 :     __ cmpl(rdi, rax);
     231          78 :     BranchOrBacktrack(less_equal, on_no_match);
     232             :   } else {
     233             :     __ movl(rax, rdi);
     234        2196 :     __ addl(rax, rbx);
     235        2196 :     BranchOrBacktrack(greater, on_no_match);
     236             :   }
     237             : 
     238        2274 :   if (mode_ == LATIN1) {
     239             :     Label loop_increment;
     240        1965 :     if (on_no_match == NULL) {
     241        1937 :       on_no_match = &backtrack_label_;
     242             :     }
     243             : 
     244        3930 :     __ leap(r9, Operand(rsi, rdx, times_1, 0));
     245        3930 :     __ leap(r11, Operand(rsi, rdi, times_1, 0));
     246        1965 :     if (read_backward) {
     247          72 :       __ subp(r11, rbx);  // Offset by length when matching backwards.
     248             :     }
     249        1965 :     __ 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        1965 :     __ bind(&loop);
     257        3930 :     __ movzxbl(rdx, Operand(r9, 0));
     258        3930 :     __ movzxbl(rax, Operand(r11, 0));
     259             :     // al - input character
     260             :     // dl - capture character
     261             :     __ cmpb(rax, rdx);
     262        1965 :     __ 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        1965 :     __ orp(rax, Immediate(0x20));  // Convert match character to lower-case.
     268        1965 :     __ orp(rdx, Immediate(0x20));  // Convert capture character to lower-case.
     269             :     __ cmpb(rax, rdx);
     270        1965 :     __ j(not_equal, on_no_match);  // Definitely not equal.
     271             :     __ subb(rax, Immediate('a'));
     272             :     __ cmpb(rax, Immediate('z' - 'a'));
     273        1965 :     __ 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        1965 :     __ j(above, on_no_match);  // Weren't Latin-1 letters.
     278             :     __ cmpb(rax, Immediate(247 - 224));  // Check for 247.
     279        1965 :     __ j(equal, on_no_match);
     280        1965 :     __ bind(&loop_increment);
     281             :     // Increment pointers into match and capture strings.
     282        1965 :     __ addp(r11, Immediate(1));
     283        1965 :     __ addp(r9, Immediate(1));
     284             :     // Compare to end of capture, and loop if not done.
     285        1965 :     __ cmpp(r9, rbx);
     286        1965 :     __ j(below, &loop);
     287             : 
     288             :     // Compute new value of character position after the matched part.
     289             :     __ movp(rdi, r11);
     290        1965 :     __ subq(rdi, rsi);
     291        1965 :     if (read_backward) {
     292             :       // Subtract match length if we matched backward.
     293          72 :       __ addq(rdi, register_location(start_reg));
     294          72 :       __ 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         309 :     __ pushq(rsi);
     302         309 :     __ pushq(rdi);
     303             : #endif
     304         309 :     __ pushq(backtrack_stackpointer());
     305             : 
     306             :     static const int num_arguments = 4;
     307         309 :     __ 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.is(arg_reg_1));
     316             :     DCHECK(rdx.is(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.is(arg_reg_1));
     326             :     DCHECK(rsi.is(arg_reg_2));
     327             :     // Compute byte_offset2 (current position = rsi+rdi).
     328         618 :     __ leap(rax, Operand(rsi, rdi, times_1, 0));
     329             :     // Compute and set byte_offset1 (start of capture).
     330         618 :     __ leap(rdi, Operand(rsi, rdx, times_1, 0));
     331             :     // Set byte_offset2.
     332             :     __ movp(rsi, rax);
     333         309 :     if (read_backward) {
     334           6 :       __ 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         309 :     if (unicode) {
     343             :       __ movp(arg_reg_4, Immediate(0));
     344             :     } else  // NOLINT
     345             : #endif      // V8_INTL_SUPPORT
     346             :     {
     347         291 :       __ 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         309 :           ExternalReference::re_case_insensitive_compare_uc16(isolate());
     355         309 :       __ CallCFunction(compare, num_arguments);
     356             :     }
     357             : 
     358             :     // Restore original values before reacting on result value.
     359         309 :     __ Move(code_object_pointer(), masm_.CodeObject());
     360         309 :     __ popq(backtrack_stackpointer());
     361             : #ifndef _WIN64
     362         309 :     __ popq(rdi);
     363         309 :     __ popq(rsi);
     364             : #endif
     365             : 
     366             :     // Check if function returned non-zero for success or zero for failure.
     367             :     __ testp(rax, rax);
     368         309 :     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         309 :     if (read_backward) {
     372           6 :       __ subq(rdi, rbx);
     373             :     } else {
     374         303 :       __ addq(rdi, rbx);
     375             :     }
     376             :   }
     377        2274 :   __ bind(&fallthrough);
     378        2274 : }
     379             : 
     380             : 
     381         776 : void RegExpMacroAssemblerX64::CheckNotBackReference(int start_reg,
     382             :                                                     bool read_backward,
     383        1552 :                                                     Label* on_no_match) {
     384             :   Label fallthrough;
     385             : 
     386             :   // Find length of back-referenced capture.
     387         776 :   ReadPositionFromRegister(rdx, start_reg);  // Offset of start of capture
     388         776 :   ReadPositionFromRegister(rax, start_reg + 1);  // Offset of end of capture
     389         776 :   __ 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         776 :   __ 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         776 :   if (read_backward) {
     401         288 :     __ movl(rbx, Operand(rbp, kStringStartMinusOne));
     402         144 :     __ addl(rbx, rax);
     403         144 :     __ cmpl(rdi, rbx);
     404         144 :     BranchOrBacktrack(less_equal, on_no_match);
     405             :   } else {
     406             :     __ movl(rbx, rdi);
     407         632 :     __ addl(rbx, rax);
     408         632 :     BranchOrBacktrack(greater, on_no_match);
     409             :   }
     410             : 
     411             :   // Compute pointers to match string and capture string
     412        1552 :   __ leap(rbx, Operand(rsi, rdi, times_1, 0));  // Start of match.
     413         776 :   if (read_backward) {
     414         144 :     __ subq(rbx, rax);  // Offset by length when matching backwards.
     415             :   }
     416         776 :   __ addp(rdx, rsi);  // Start of capture.
     417        1552 :   __ 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         776 :   __ bind(&loop);
     426         776 :   if (mode_ == LATIN1) {
     427        1368 :     __ movzxbl(rax, Operand(rdx, 0));
     428        1368 :     __ cmpb(rax, Operand(rbx, 0));
     429             :   } else {
     430             :     DCHECK(mode_ == UC16);
     431         184 :     __ movzxwl(rax, Operand(rdx, 0));
     432         184 :     __ cmpw(rax, Operand(rbx, 0));
     433             :   }
     434         776 :   BranchOrBacktrack(not_equal, on_no_match);
     435             :   // Increment pointers into capture and match string.
     436         776 :   __ addp(rbx, Immediate(char_size()));
     437         776 :   __ addp(rdx, Immediate(char_size()));
     438             :   // Check if we have reached end of match area.
     439         776 :   __ cmpp(rdx, r9);
     440         776 :   __ j(below, &loop);
     441             : 
     442             :   // Success.
     443             :   // Set current character position to position after match.
     444             :   __ movp(rdi, rbx);
     445         776 :   __ subq(rdi, rsi);
     446         776 :   if (read_backward) {
     447             :     // Subtract match length if we matched backward.
     448         144 :     __ addq(rdi, register_location(start_reg));
     449         144 :     __ subq(rdi, register_location(start_reg + 1));
     450             :   }
     451             : 
     452         776 :   __ bind(&fallthrough);
     453         776 : }
     454             : 
     455             : 
     456      675659 : void RegExpMacroAssemblerX64::CheckNotCharacter(uint32_t c,
     457             :                                                 Label* on_not_equal) {
     458     1351318 :   __ cmpl(current_character(), Immediate(c));
     459      675659 :   BranchOrBacktrack(not_equal, on_not_equal);
     460      675659 : }
     461             : 
     462             : 
     463       61900 : void RegExpMacroAssemblerX64::CheckCharacterAfterAnd(uint32_t c,
     464             :                                                      uint32_t mask,
     465             :                                                      Label* on_equal) {
     466       61900 :   if (c == 0) {
     467        1850 :     __ testl(current_character(), Immediate(mask));
     468             :   } else {
     469       60050 :     __ movl(rax, Immediate(mask));
     470       60050 :     __ andp(rax, current_character());
     471      120100 :     __ cmpl(rax, Immediate(c));
     472             :   }
     473       61900 :   BranchOrBacktrack(equal, on_equal);
     474       61900 : }
     475             : 
     476             : 
     477       19227 : void RegExpMacroAssemblerX64::CheckNotCharacterAfterAnd(uint32_t c,
     478             :                                                         uint32_t mask,
     479             :                                                         Label* on_not_equal) {
     480       19227 :   if (c == 0) {
     481         633 :     __ testl(current_character(), Immediate(mask));
     482             :   } else {
     483       18594 :     __ movl(rax, Immediate(mask));
     484       18594 :     __ andp(rax, current_character());
     485       37188 :     __ cmpl(rax, Immediate(c));
     486             :   }
     487       19227 :   BranchOrBacktrack(not_equal, on_not_equal);
     488       19227 : }
     489             : 
     490             : 
     491         104 : void RegExpMacroAssemblerX64::CheckNotCharacterAfterMinusAnd(
     492             :     uc16 c,
     493             :     uc16 minus,
     494             :     uc16 mask,
     495             :     Label* on_not_equal) {
     496             :   DCHECK(minus < String::kMaxUtf16CodeUnit);
     497         208 :   __ leap(rax, Operand(current_character(), -minus));
     498         208 :   __ andp(rax, Immediate(mask));
     499         208 :   __ cmpl(rax, Immediate(c));
     500         104 :   BranchOrBacktrack(not_equal, on_not_equal);
     501         104 : }
     502             : 
     503             : 
     504       27472 : void RegExpMacroAssemblerX64::CheckCharacterInRange(
     505             :     uc16 from,
     506             :     uc16 to,
     507             :     Label* on_in_range) {
     508       54944 :   __ leal(rax, Operand(current_character(), -from));
     509       54944 :   __ cmpl(rax, Immediate(to - from));
     510       27472 :   BranchOrBacktrack(below_equal, on_in_range);
     511       27472 : }
     512             : 
     513             : 
     514      108045 : void RegExpMacroAssemblerX64::CheckCharacterNotInRange(
     515             :     uc16 from,
     516             :     uc16 to,
     517             :     Label* on_not_in_range) {
     518      216090 :   __ leal(rax, Operand(current_character(), -from));
     519      216090 :   __ cmpl(rax, Immediate(to - from));
     520      108045 :   BranchOrBacktrack(above, on_not_in_range);
     521      108045 : }
     522             : 
     523             : 
     524       12826 : void RegExpMacroAssemblerX64::CheckBitInTable(
     525             :     Handle<ByteArray> table,
     526             :     Label* on_bit_set) {
     527       12826 :   __ Move(rax, table);
     528             :   Register index = current_character();
     529             :   if (mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) {
     530       12826 :     __ movp(rbx, current_character());
     531       12826 :     __ andp(rbx, Immediate(kTableMask));
     532             :     index = rbx;
     533             :   }
     534             :   __ cmpb(FieldOperand(rax, index, times_1, ByteArray::kHeaderSize),
     535       25652 :           Immediate(0));
     536       12826 :   BranchOrBacktrack(not_equal, on_bit_set);
     537       12826 : }
     538             : 
     539             : 
     540       19993 : 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       19993 :   switch (type) {
     547             :   case 's':
     548             :     // Match space-characters
     549        2731 :     if (mode_ == LATIN1) {
     550             :       // One byte space characters are '\t'..'\r', ' ' and \u00a0.
     551             :       Label success;
     552        2633 :       __ cmpl(current_character(), Immediate(' '));
     553        2633 :       __ j(equal, &success, Label::kNear);
     554             :       // Check range 0x09..0x0d
     555        5266 :       __ leap(rax, Operand(current_character(), -'\t'));
     556        2633 :       __ cmpl(rax, Immediate('\r' - '\t'));
     557        2633 :       __ j(below_equal, &success, Label::kNear);
     558             :       // \u00a0 (NBSP).
     559        2633 :       __ cmpl(rax, Immediate(0x00a0 - '\t'));
     560        2633 :       BranchOrBacktrack(not_equal, on_no_match);
     561        2633 :       __ 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           0 :     __ leap(rax, Operand(current_character(), -'0'));
     571           0 :     __ cmpl(rax, Immediate('9' - '0'));
     572           0 :     BranchOrBacktrack(above, on_no_match);
     573           0 :     return true;
     574             :   case 'D':
     575             :     // Match non ASCII-digits
     576           0 :     __ leap(rax, Operand(current_character(), -'0'));
     577           0 :     __ cmpl(rax, Immediate('9' - '0'));
     578           0 :     BranchOrBacktrack(below_equal, on_no_match);
     579           0 :     return true;
     580             :   case '.': {
     581             :     // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
     582       10479 :     __ movl(rax, current_character());
     583       10479 :     __ xorp(rax, Immediate(0x01));
     584             :     // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
     585       10479 :     __ subl(rax, Immediate(0x0b));
     586       10479 :     __ cmpl(rax, Immediate(0x0c - 0x0b));
     587       10479 :     BranchOrBacktrack(below_equal, on_no_match);
     588       10479 :     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         463 :       __ subl(rax, Immediate(0x2028 - 0x0b));
     593         463 :       __ cmpl(rax, Immediate(0x2029 - 0x2028));
     594         463 :       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         893 :     __ movl(rax, current_character());
     601         893 :     __ xorp(rax, Immediate(0x01));
     602             :     // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
     603         893 :     __ subl(rax, Immediate(0x0b));
     604         893 :     __ cmpl(rax, Immediate(0x0c - 0x0b));
     605         893 :     if (mode_ == LATIN1) {
     606         859 :       BranchOrBacktrack(above, on_no_match);
     607             :     } else {
     608             :       Label done;
     609          34 :       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          34 :       __ subl(rax, Immediate(0x2028 - 0x0b));
     614          34 :       __ cmpl(rax, Immediate(0x2029 - 0x2028));
     615          34 :       BranchOrBacktrack(above, on_no_match);
     616          34 :       __ bind(&done);
     617             :     }
     618             :     return true;
     619             :   }
     620             :   case 'w': {
     621        4978 :     if (mode_ != LATIN1) {
     622             :       // Table is 256 entries, so all Latin1 characters can be tested.
     623          54 :       __ cmpl(current_character(), Immediate('z'));
     624          54 :       BranchOrBacktrack(above, on_no_match);
     625             :     }
     626        4978 :     __ Move(rbx, ExternalReference::re_word_character_map());
     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        4978 :              current_character());
     630        4978 :     BranchOrBacktrack(zero, on_no_match);
     631        4978 :     return true;
     632             :   }
     633             :   case 'W': {
     634             :     Label done;
     635         631 :     if (mode_ != LATIN1) {
     636             :       // Table is 256 entries, so all Latin1 characters can be tested.
     637          88 :       __ cmpl(current_character(), Immediate('z'));
     638          88 :       __ j(above, &done);
     639             :     }
     640         631 :     __ Move(rbx, ExternalReference::re_word_character_map());
     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         631 :              current_character());
     644         631 :     BranchOrBacktrack(not_zero, on_no_match);
     645         631 :     if (mode_ != LATIN1) {
     646          88 :       __ bind(&done);
     647             :     }
     648             :     return true;
     649             :   }
     650             : 
     651             :   case '*':
     652             :     // Match any character.
     653           0 :     return true;
     654             :   // No custom implementation (yet): s(UC16), S(UC16).
     655             :   default:
     656             :     return false;
     657             :   }
     658             : }
     659             : 
     660             : 
     661       92265 : void RegExpMacroAssemblerX64::Fail() {
     662             :   STATIC_ASSERT(FAILURE == 0);  // Return value for failure is zero.
     663       92265 :   if (!global()) {
     664       87172 :     __ Set(rax, FAILURE);
     665             :   }
     666       92265 :   __ jmp(&exit_label_);
     667       92265 : }
     668             : 
     669             : 
     670       92258 : 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       92258 :   __ bind(&entry_label_);
     676             : 
     677             :   // Tell the system that we have a stack frame.  Because the type is MANUAL, no
     678             :   // is generated.
     679      184516 :   FrameScope scope(&masm_, StackFrame::MANUAL);
     680             : 
     681             :   // Actually emit code to start a new stack frame.
     682       92258 :   __ 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       92258 :   __ pushq(rdi);
     707       92258 :   __ pushq(rsi);
     708       92258 :   __ pushq(rdx);
     709       92258 :   __ pushq(rcx);
     710       92258 :   __ pushq(r8);
     711       92258 :   __ pushq(r9);
     712             : 
     713       92258 :   __ pushq(rbx);  // Callee-save
     714             : #endif
     715             : 
     716       92258 :   __ Push(Immediate(0));  // Number of successful matches in a global regexp.
     717       92258 :   __ 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       92258 :       ExternalReference::address_of_stack_limit(isolate());
     725             :   __ movp(rcx, rsp);
     726             :   __ Move(kScratchRegister, stack_limit);
     727      184516 :   __ subp(rcx, Operand(kScratchRegister, 0));
     728             :   // Handle it if the stack pointer is already below the stack limit.
     729       92258 :   __ j(below_equal, &stack_limit_hit);
     730             :   // Check if there is room for the variable number of registers above
     731             :   // the stack limit.
     732      184516 :   __ cmpp(rcx, Immediate(num_registers_ * kPointerSize));
     733       92258 :   __ j(above_equal, &stack_ok);
     734             :   // Exit with OutOfMemory exception. There is not enough space on the stack
     735             :   // for our working registers.
     736       92258 :   __ Set(rax, EXCEPTION);
     737       92258 :   __ jmp(&return_rax);
     738             : 
     739       92258 :   __ bind(&stack_limit_hit);
     740       92258 :   __ Move(code_object_pointer(), masm_.CodeObject());
     741       92258 :   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       92258 :   __ j(not_zero, &return_rax);
     745             : 
     746       92258 :   __ bind(&stack_ok);
     747             : 
     748             :   // Allocate space on stack for registers.
     749      184516 :   __ subp(rsp, Immediate(num_registers_ * kPointerSize));
     750             :   // Load string length.
     751      184516 :   __ movp(rsi, Operand(rbp, kInputEnd));
     752             :   // Load input position.
     753      184516 :   __ movp(rdi, Operand(rbp, kInputStart));
     754             :   // Set up rdi to be negative offset from string end.
     755       92258 :   __ subq(rdi, rsi);
     756             :   // Set rax to address of char before start of the string
     757             :   // (effectively string position -1).
     758      184516 :   __ movp(rbx, Operand(rbp, kStartIndex));
     759             :   __ negq(rbx);
     760       92258 :   if (mode_ == UC16) {
     761      144418 :     __ leap(rax, Operand(rdi, rbx, times_2, -char_size()));
     762             :   } else {
     763       40098 :     __ 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      184516 :   __ 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       92258 :   __ 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      184516 :   __ cmpl(Operand(rbp, kStartIndex), Immediate(0));
     787       92258 :   __ j(not_equal, &load_char_start_regexp, Label::kNear);
     788       92258 :   __ Set(current_character(), '\n');
     789       92258 :   __ jmp(&start_regexp, Label::kNear);
     790             : 
     791             :   // Global regexp restarts matching here.
     792       92258 :   __ bind(&load_char_start_regexp);
     793             :   // Load previous char as initial value of current character register.
     794       92258 :   LoadCurrentCharacterUnchecked(-1, 1);
     795       92258 :   __ bind(&start_regexp);
     796             : 
     797             :   // Initialize on-stack registers.
     798       92258 :   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       92237 :     if (num_saved_registers_ > 8) {
     803        1122 :       __ Set(rcx, kRegisterZero);
     804             :       Label init_loop;
     805        1122 :       __ bind(&init_loop);
     806        2244 :       __ movp(Operand(rbp, rcx, times_1, 0), rax);
     807        1122 :       __ subq(rcx, Immediate(kPointerSize));
     808             :       __ cmpq(rcx,
     809        2244 :               Immediate(kRegisterZero - num_saved_registers_ * kPointerSize));
     810        1122 :       __ j(greater, &init_loop);
     811             :     } else {  // Unroll the loop.
     812      204250 :       for (int i = 0; i < num_saved_registers_; i++) {
     813      204250 :         __ movp(register_location(i), rax);
     814             :       }
     815             :     }
     816             :   }
     817             : 
     818             :   // Initialize backtrack stack pointer.
     819      184516 :   __ movp(backtrack_stackpointer(), Operand(rbp, kStackHighEnd));
     820             : 
     821       92258 :   __ jmp(&start_label_);
     822             : 
     823             :   // Exit code:
     824       92258 :   if (success_label_.is_linked()) {
     825             :     // Save captures when successful.
     826       91882 :     __ bind(&success_label_);
     827       91882 :     if (num_saved_registers_ > 0) {
     828             :       // copy captures to output
     829      183736 :       __ movp(rdx, Operand(rbp, kStartIndex));
     830      183736 :       __ movp(rbx, Operand(rbp, kRegisterOutput));
     831      183736 :       __ movp(rcx, Operand(rbp, kInputEnd));
     832      183736 :       __ subp(rcx, Operand(rbp, kInputStart));
     833       91868 :       if (mode_ == UC16) {
     834      144418 :         __ leap(rcx, Operand(rcx, rdx, times_2, 0));
     835             :       } else {
     836       19659 :         __ addp(rcx, rdx);
     837             :       }
     838      264642 :       for (int i = 0; i < num_saved_registers_; i++) {
     839      264642 :         __ movp(rax, register_location(i));
     840      545907 :         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      264642 :         __ addp(rax, rcx);  // Convert to index from start, not end.
     845      264642 :         if (mode_ == UC16) {
     846             :           __ sarp(rax, Immediate(1));  // Convert byte index to character index.
     847             :         }
     848      529284 :         __ movl(Operand(rbx, i * kIntSize), rax);
     849             :       }
     850             :     }
     851             : 
     852       91882 :     if (global()) {
     853             :       // Restart matching if the regular expression is flagged as global.
     854             :       // Increment success counter.
     855       10184 :       __ 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        5092 :       __ movsxlq(rcx, Operand(rbp, kNumOutputRegisters));
     859       10184 :       __ subp(rcx, Immediate(num_saved_registers_));
     860             :       // Check whether we have enough room for another set of capture results.
     861       10184 :       __ cmpp(rcx, Immediate(num_saved_registers_));
     862        5092 :       __ j(less, &exit_label_);
     863             : 
     864       10184 :       __ movp(Operand(rbp, kNumOutputRegisters), rcx);
     865             :       // Advance the location for output.
     866             :       __ addp(Operand(rbp, kRegisterOutput),
     867       10184 :               Immediate(num_saved_registers_ * kIntSize));
     868             : 
     869             :       // Prepare rax to initialize registers with its value in the next run.
     870       10184 :       __ movp(rax, Operand(rbp, kStringStartMinusOne));
     871             : 
     872        5092 :       if (global_with_zero_length_check()) {
     873             :         // Special case for zero-length matches.
     874             :         // rdx: capture start index
     875         165 :         __ cmpp(rdi, rdx);
     876             :         // Not a zero-length match, restart.
     877         165 :         __ 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         165 :         __ j(zero, &exit_label_, Label::kNear);
     881             :         // Advance current position after a zero-length match.
     882             :         Label advance;
     883         165 :         __ bind(&advance);
     884         165 :         if (mode_ == UC16) {
     885          27 :           __ addq(rdi, Immediate(2));
     886             :         } else {
     887             :           __ incq(rdi);
     888             :         }
     889         165 :         if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
     890             :       }
     891             : 
     892        5092 :       __ jmp(&load_char_start_regexp);
     893             :     } else {
     894             :       __ movp(rax, Immediate(SUCCESS));
     895             :     }
     896             :   }
     897             : 
     898       92258 :   __ bind(&exit_label_);
     899       92258 :   if (global()) {
     900             :     // Return the number of successful captures.
     901       10186 :     __ movp(rax, Operand(rbp, kSuccessfulCaptures));
     902             :   }
     903             : 
     904       92258 :   __ 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      184516 :   __ 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       92258 :   __ popq(rbp);
     920       92258 :   __ ret(0);
     921             : 
     922             :   // Backtrack code (branch target for conditional backtracks).
     923       92258 :   if (backtrack_label_.is_linked()) {
     924       91845 :     __ bind(&backtrack_label_);
     925       91845 :     Backtrack();
     926             :   }
     927             : 
     928             :   Label exit_with_exception;
     929             : 
     930             :   // Preempt-code
     931       92258 :   if (check_preempt_label_.is_linked()) {
     932       92209 :     SafeCallTarget(&check_preempt_label_);
     933             : 
     934       92209 :     __ pushq(backtrack_stackpointer());
     935       92209 :     __ pushq(rdi);
     936             : 
     937       92209 :     CallCheckStackGuardState();
     938             :     __ testp(rax, rax);
     939             :     // If returning non-zero, we should end execution with the given
     940             :     // result as return value.
     941       92209 :     __ j(not_zero, &return_rax);
     942             : 
     943             :     // Restore registers.
     944       92209 :     __ Move(code_object_pointer(), masm_.CodeObject());
     945       92209 :     __ popq(rdi);
     946       92209 :     __ popq(backtrack_stackpointer());
     947             :     // String might have moved: Reload esi from frame.
     948      184418 :     __ movp(rsi, Operand(rbp, kInputEnd));
     949       92209 :     SafeReturn();
     950             :   }
     951             : 
     952             :   // Backtrack stack overflow code.
     953       92258 :   if (stack_overflow_label_.is_linked()) {
     954       92216 :     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       92216 :     __ pushq(rsi);
     962       92216 :     __ pushq(rdi);
     963             : #endif
     964             : 
     965             :     // Call GrowStack(backtrack_stackpointer())
     966             :     static const int num_arguments = 3;
     967       92216 :     __ 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      184432 :     __ leap(rsi, Operand(rbp, kStackHighEnd));  // Second argument.
     977       92216 :     __ LoadAddress(rdx, ExternalReference::isolate_address(isolate()));
     978             : #endif
     979             :     ExternalReference grow_stack =
     980       92216 :         ExternalReference::re_grow_stack(isolate());
     981       92216 :     __ CallCFunction(grow_stack, num_arguments);
     982             :     // If return NULL, we have failed to grow the stack, and
     983             :     // must exit with a stack-overflow exception.
     984             :     __ testp(rax, rax);
     985       92216 :     __ 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       92216 :     __ Move(code_object_pointer(), masm_.CodeObject());
     990             : #ifndef _WIN64
     991       92216 :     __ popq(rdi);
     992       92216 :     __ popq(rsi);
     993             : #endif
     994       92216 :     SafeReturn();
     995             :   }
     996             : 
     997       92258 :   if (exit_with_exception.is_linked()) {
     998             :     // If any of the code above needed to exit with an exception.
     999       92216 :     __ bind(&exit_with_exception);
    1000             :     // Exit with Result EXCEPTION(-1) to signal thrown exception.
    1001       92216 :     __ Set(rax, EXCEPTION);
    1002       92216 :     __ jmp(&return_rax);
    1003             :   }
    1004             : 
    1005       92258 :   FixupCodeRelativePositions();
    1006             : 
    1007             :   CodeDesc code_desc;
    1008       92258 :   masm_.GetCode(&code_desc);
    1009             :   Isolate* isolate = this->isolate();
    1010             :   Handle<Code> code = isolate->factory()->NewCode(
    1011             :       code_desc, Code::ComputeFlags(Code::REGEXP),
    1012       92258 :       masm_.CodeObject());
    1013       92258 :   PROFILE(isolate, RegExpCodeCreateEvent(AbstractCode::cast(*code), *source));
    1014       92258 :   return Handle<HeapObject>::cast(code);
    1015             : }
    1016             : 
    1017             : 
    1018     1402947 : void RegExpMacroAssemblerX64::GoTo(Label* to) {
    1019     1402947 :   BranchOrBacktrack(no_condition, to);
    1020     1402947 : }
    1021             : 
    1022             : 
    1023        4590 : void RegExpMacroAssemblerX64::IfRegisterGE(int reg,
    1024             :                                            int comparand,
    1025             :                                            Label* if_ge) {
    1026        4590 :   __ cmpp(register_location(reg), Immediate(comparand));
    1027        4590 :   BranchOrBacktrack(greater_equal, if_ge);
    1028        4590 : }
    1029             : 
    1030             : 
    1031        3425 : void RegExpMacroAssemblerX64::IfRegisterLT(int reg,
    1032             :                                            int comparand,
    1033             :                                            Label* if_lt) {
    1034        3425 :   __ cmpp(register_location(reg), Immediate(comparand));
    1035        3425 :   BranchOrBacktrack(less, if_lt);
    1036        3425 : }
    1037             : 
    1038             : 
    1039         374 : void RegExpMacroAssemblerX64::IfRegisterEqPos(int reg,
    1040             :                                               Label* if_eq) {
    1041         374 :   __ cmpp(rdi, register_location(reg));
    1042         374 :   BranchOrBacktrack(equal, if_eq);
    1043         374 : }
    1044             : 
    1045             : 
    1046             : RegExpMacroAssembler::IrregexpImplementation
    1047           0 :     RegExpMacroAssemblerX64::Implementation() {
    1048           0 :   return kX64Implementation;
    1049             : }
    1050             : 
    1051             : 
    1052     1035869 : void RegExpMacroAssemblerX64::LoadCurrentCharacter(int cp_offset,
    1053             :                                                    Label* on_end_of_input,
    1054             :                                                    bool check_bounds,
    1055             :                                                    int characters) {
    1056             :   DCHECK(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
    1057     1035869 :   if (check_bounds) {
    1058      506217 :     if (cp_offset >= 0) {
    1059      502393 :       CheckPosition(cp_offset + characters - 1, on_end_of_input);
    1060             :     } else {
    1061        3824 :       CheckPosition(cp_offset, on_end_of_input);
    1062             :     }
    1063             :   }
    1064     1035869 :   LoadCurrentCharacterUnchecked(cp_offset, characters);
    1065     1035869 : }
    1066             : 
    1067             : 
    1068      474458 : void RegExpMacroAssemblerX64::PopCurrentPosition() {
    1069      474458 :   Pop(rdi);
    1070      474458 : }
    1071             : 
    1072             : 
    1073       86096 : void RegExpMacroAssemblerX64::PopRegister(int register_index) {
    1074       86096 :   Pop(rax);
    1075       86096 :   __ movp(register_location(register_index), rax);
    1076       86096 : }
    1077             : 
    1078             : 
    1079      687543 : void RegExpMacroAssemblerX64::PushBacktrack(Label* label) {
    1080      687543 :   Push(label);
    1081      687543 :   CheckStackLimit();
    1082      687543 : }
    1083             : 
    1084             : 
    1085      490491 : void RegExpMacroAssemblerX64::PushCurrentPosition() {
    1086      490491 :   Push(rdi);
    1087      490491 : }
    1088             : 
    1089             : 
    1090       86117 : void RegExpMacroAssemblerX64::PushRegister(int register_index,
    1091             :                                            StackCheckFlag check_stack_limit) {
    1092       86117 :   __ movp(rax, register_location(register_index));
    1093       86117 :   Push(rax);
    1094       86117 :   if (check_stack_limit) CheckStackLimit();
    1095       86117 : }
    1096             : 
    1097             : 
    1098             : STATIC_ASSERT(kPointerSize == kInt64Size || kPointerSize == kInt32Size);
    1099             : 
    1100             : 
    1101        5368 : void RegExpMacroAssemblerX64::ReadCurrentPositionFromRegister(int reg) {
    1102             :   if (kPointerSize == kInt64Size) {
    1103        5368 :     __ 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        5368 : }
    1109             : 
    1110             : 
    1111        6100 : void RegExpMacroAssemblerX64::ReadPositionFromRegister(Register dst, int reg) {
    1112             :   if (kPointerSize == kInt64Size) {
    1113        6100 :     __ 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        6100 : }
    1119             : 
    1120             : 
    1121        5361 : void RegExpMacroAssemblerX64::ReadStackPointerFromRegister(int reg) {
    1122        5361 :   __ movp(backtrack_stackpointer(), register_location(reg));
    1123       10722 :   __ addp(backtrack_stackpointer(), Operand(rbp, kStackHighEnd));
    1124        5361 : }
    1125             : 
    1126             : 
    1127         729 : void RegExpMacroAssemblerX64::SetCurrentPositionFromEnd(int by) {
    1128             :   Label after_position;
    1129         729 :   __ cmpp(rdi, Immediate(-by * char_size()));
    1130         243 :   __ j(greater_equal, &after_position, Label::kNear);
    1131         243 :   __ 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         243 :   LoadCurrentCharacterUnchecked(-1, 1);
    1136         243 :   __ bind(&after_position);
    1137         243 : }
    1138             : 
    1139             : 
    1140        6240 : void RegExpMacroAssemblerX64::SetRegister(int register_index, int to) {
    1141             :   DCHECK(register_index >= num_saved_registers_);  // Reserved for positions!
    1142        6240 :   __ movp(register_location(register_index), Immediate(to));
    1143        6240 : }
    1144             : 
    1145             : 
    1146      103382 : bool RegExpMacroAssemblerX64::Succeed() {
    1147      103382 :   __ jmp(&success_label_);
    1148      206764 :   return global();
    1149             : }
    1150             : 
    1151             : 
    1152      523589 : void RegExpMacroAssemblerX64::WriteCurrentPositionToRegister(int reg,
    1153      241681 :                                                              int cp_offset) {
    1154      523589 :   if (cp_offset == 0) {
    1155      281908 :     __ movp(register_location(reg), rdi);
    1156             :   } else {
    1157      483362 :     __ leap(rax, Operand(rdi, cp_offset * char_size()));
    1158      241681 :     __ movp(register_location(reg), rax);
    1159             :   }
    1160      523589 : }
    1161             : 
    1162             : 
    1163      173605 : void RegExpMacroAssemblerX64::ClearRegisters(int reg_from, int reg_to) {
    1164             :   DCHECK(reg_from <= reg_to);
    1165      347210 :   __ movp(rax, Operand(rbp, kStringStartMinusOne));
    1166      506694 :   for (int reg = reg_from; reg <= reg_to; reg++) {
    1167      333089 :     __ movp(register_location(reg), rax);
    1168             :   }
    1169      173605 : }
    1170             : 
    1171             : 
    1172        5319 : void RegExpMacroAssemblerX64::WriteStackPointerToRegister(int reg) {
    1173        5319 :   __ movp(rax, backtrack_stackpointer());
    1174       10638 :   __ subp(rax, Operand(rbp, kStackHighEnd));
    1175        5319 :   __ movp(register_location(reg), rax);
    1176        5319 : }
    1177             : 
    1178             : 
    1179             : // Private methods:
    1180             : 
    1181      184467 : 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      184467 :   __ 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, -kPointerSize));
    1194             : #else
    1195             :   // Third argument: RegExp code frame pointer.
    1196      184467 :   __ 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      368934 :   __ leap(rdi, Operand(rsp, -kRegisterSize));
    1202             : #endif
    1203             :   ExternalReference stack_check =
    1204      184467 :       ExternalReference::re_check_stack_guard_state(isolate());
    1205      184467 :   __ CallCFunction(stack_check, num_arguments);
    1206      184467 : }
    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             :   return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
    1213             : }
    1214             : 
    1215             : 
    1216             : template <typename T>
    1217             : static T* frame_entry_address(Address re_frame, int frame_offset) {
    1218             :   return reinterpret_cast<T*>(re_frame + frame_offset);
    1219             : }
    1220             : 
    1221             : 
    1222         440 : int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
    1223             :                                                   Code* re_code,
    1224             :                                                   Address re_frame) {
    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<String*>(re_frame, kInputString),
    1230             :       frame_entry_address<const byte*>(re_frame, kInputStart),
    1231         440 :       frame_entry_address<const byte*>(re_frame, kInputEnd));
    1232             : }
    1233             : 
    1234             : 
    1235     1542311 : Operand RegExpMacroAssemblerX64::register_location(int register_index) {
    1236             :   DCHECK(register_index < (1<<30));
    1237     1542311 :   if (num_registers_ <= register_index) {
    1238        7040 :     num_registers_ = register_index + 1;
    1239             :   }
    1240     1542311 :   return Operand(rbp, kRegisterZero - register_index * kPointerSize);
    1241             : }
    1242             : 
    1243             : 
    1244      569741 : void RegExpMacroAssemblerX64::CheckPosition(int cp_offset,
    1245      569741 :                                             Label* on_outside_input) {
    1246      569741 :   if (cp_offset >= 0) {
    1247     1697733 :     __ cmpl(rdi, Immediate(-cp_offset * char_size()));
    1248      565911 :     BranchOrBacktrack(greater_equal, on_outside_input);
    1249             :   } else {
    1250        7660 :     __ leap(rax, Operand(rdi, cp_offset * char_size()));
    1251        7660 :     __ cmpp(rax, Operand(rbp, kStringStartMinusOne));
    1252        3830 :     BranchOrBacktrack(less_equal, on_outside_input);
    1253             :   }
    1254      569741 : }
    1255             : 
    1256             : 
    1257     3149679 : void RegExpMacroAssemblerX64::BranchOrBacktrack(Condition condition,
    1258             :                                                 Label* to) {
    1259     3149679 :   if (condition < 0) {  // No condition
    1260     1418994 :     if (to == NULL) {
    1261       21236 :       Backtrack();
    1262       21236 :       return;
    1263             :     }
    1264     1397758 :     __ jmp(to);
    1265     1397758 :     return;
    1266             :   }
    1267     1730685 :   if (to == NULL) {
    1268      566242 :     __ j(condition, &backtrack_label_);
    1269      566242 :     return;
    1270             :   }
    1271     1164443 :   __ j(condition, to);
    1272             : }
    1273             : 
    1274             : 
    1275             : void RegExpMacroAssemblerX64::SafeCall(Label* to) {
    1276      928889 :   __ call(to);
    1277             : }
    1278             : 
    1279             : 
    1280      184425 : void RegExpMacroAssemblerX64::SafeCallTarget(Label* label) {
    1281      184425 :   __ bind(label);
    1282      368850 :   __ subp(Operand(rsp, 0), code_object_pointer());
    1283      184425 : }
    1284             : 
    1285             : 
    1286      184425 : void RegExpMacroAssemblerX64::SafeReturn() {
    1287      368850 :   __ addp(Operand(rsp, 0), code_object_pointer());
    1288      184425 :   __ ret(0);
    1289      184425 : }
    1290             : 
    1291             : 
    1292      576608 : void RegExpMacroAssemblerX64::Push(Register source) {
    1293             :   DCHECK(!source.is(backtrack_stackpointer()));
    1294             :   // Notice: This updates flags, unlike normal Push.
    1295      576608 :   __ subp(backtrack_stackpointer(), Immediate(kIntSize));
    1296     1153216 :   __ movl(Operand(backtrack_stackpointer(), 0), source);
    1297      576608 : }
    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       92258 : void RegExpMacroAssemblerX64::FixupCodeRelativePositions() {
    1308      779801 :   for (int i = 0, n = code_relative_fixup_positions_.length(); i < n; i++) {
    1309      687543 :     int position = code_relative_fixup_positions_[i];
    1310             :     // The position succeeds a relative label offset from position.
    1311             :     // Patch the relative offset to be relative to the Code object pointer
    1312             :     // instead.
    1313      687543 :     int patch_position = position - kIntSize;
    1314      687543 :     int offset = masm_.long_at(patch_position);
    1315             :     masm_.long_at_put(patch_position,
    1316             :                        offset
    1317      687543 :                        + position
    1318             :                        + Code::kHeaderSize
    1319      687543 :                        - kHeapObjectTag);
    1320             :   }
    1321             :   code_relative_fixup_positions_.Clear();
    1322       92258 : }
    1323             : 
    1324             : 
    1325      687543 : void RegExpMacroAssemblerX64::Push(Label* backtrack_target) {
    1326      687543 :   __ subp(backtrack_stackpointer(), Immediate(kIntSize));
    1327      687543 :   __ movl(Operand(backtrack_stackpointer(), 0), backtrack_target);
    1328      687543 :   MarkPositionForCodeRelativeFixup();
    1329      687543 : }
    1330             : 
    1331             : 
    1332      798666 : void RegExpMacroAssemblerX64::Pop(Register target) {
    1333             :   DCHECK(!target.is(backtrack_stackpointer()));
    1334      798666 :   __ movsxlq(target, Operand(backtrack_stackpointer(), 0));
    1335             :   // Notice: This updates flags, unlike normal Pop.
    1336      798666 :   __ addp(backtrack_stackpointer(), Immediate(kIntSize));
    1337      798666 : }
    1338             : 
    1339             : 
    1340             : void RegExpMacroAssemblerX64::Drop() {
    1341       16047 :   __ addp(backtrack_stackpointer(), Immediate(kIntSize));
    1342             : }
    1343             : 
    1344             : 
    1345      238112 : void RegExpMacroAssemblerX64::CheckPreemption() {
    1346             :   // Check for preemption.
    1347             :   Label no_preempt;
    1348             :   ExternalReference stack_limit =
    1349      238112 :       ExternalReference::address_of_stack_limit(isolate());
    1350      238112 :   __ load_rax(stack_limit);
    1351      238112 :   __ cmpp(rsp, rax);
    1352      238112 :   __ j(above, &no_preempt);
    1353             : 
    1354      238112 :   SafeCall(&check_preempt_label_);
    1355             : 
    1356      238112 :   __ bind(&no_preempt);
    1357      238112 : }
    1358             : 
    1359             : 
    1360      690777 : void RegExpMacroAssemblerX64::CheckStackLimit() {
    1361             :   Label no_stack_overflow;
    1362             :   ExternalReference stack_limit =
    1363      690777 :       ExternalReference::address_of_regexp_stack_limit(isolate());
    1364      690777 :   __ load_rax(stack_limit);
    1365      690777 :   __ cmpp(backtrack_stackpointer(), rax);
    1366      690777 :   __ j(above, &no_stack_overflow);
    1367             : 
    1368      690777 :   SafeCall(&stack_overflow_label_);
    1369             : 
    1370      690777 :   __ bind(&no_stack_overflow);
    1371      690777 : }
    1372             : 
    1373             : 
    1374     1128370 : void RegExpMacroAssemblerX64::LoadCurrentCharacterUnchecked(int cp_offset,
    1375             :                                                             int characters) {
    1376     1128370 :   if (mode_ == LATIN1) {
    1377      916504 :     if (characters == 4) {
    1378       17306 :       __ movl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
    1379      907851 :     } else if (characters == 2) {
    1380      384594 :       __ movzxwl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
    1381             :     } else {
    1382             :       DCHECK(characters == 1);
    1383     1431108 :       __ movzxbl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
    1384             :     }
    1385             :   } else {
    1386             :     DCHECK(mode_ == UC16);
    1387      211866 :     if (characters == 2) {
    1388             :       __ movl(current_character(),
    1389        3598 :               Operand(rsi, rdi, times_1, cp_offset * sizeof(uc16)));
    1390             :     } else {
    1391             :       DCHECK(characters == 1);
    1392             :       __ movzxwl(current_character(),
    1393      420134 :                  Operand(rsi, rdi, times_1, cp_offset * sizeof(uc16)));
    1394             :     }
    1395             :   }
    1396     1128370 : }
    1397             : 
    1398             : #undef __
    1399             : 
    1400             : #endif  // V8_INTERPRETED_REGEXP
    1401             : 
    1402             : }  // namespace internal
    1403             : }  // namespace v8
    1404             : 
    1405             : #endif  // V8_TARGET_ARCH_X64

Generated by: LCOV version 1.10