| Index: src/regexp/arm64/regexp-macro-assembler-arm64.cc | 
| diff --git a/src/regexp/arm64/regexp-macro-assembler-arm64.cc b/src/regexp/arm64/regexp-macro-assembler-arm64.cc | 
| index d440879e26f87f00c74dcbf8e8ea0e4a52440fd7..3c20956e6fbdb1d53384c3364c7ff9528d0dff12 100644 | 
| --- a/src/regexp/arm64/regexp-macro-assembler-arm64.cc | 
| +++ b/src/regexp/arm64/regexp-macro-assembler-arm64.cc | 
| @@ -210,22 +210,22 @@ void RegExpMacroAssemblerARM64::CheckCharacterGT(uc16 limit, | 
|  | 
|  | 
| void RegExpMacroAssemblerARM64::CheckAtStart(Label* on_at_start) { | 
| -  Label not_at_start; | 
| -  // Did we start the match at the start of the input string? | 
| -  CompareAndBranchOrBacktrack(start_offset(), 0, ne, ¬_at_start); | 
| -  // If we did, are we still at the start of the input string? | 
| __ Add(x10, input_end(), Operand(current_input_offset(), SXTW)); | 
| +  for (int i = 0; i < char_size(); i++) { | 
| +    __ Add(x10, x10, Operand(start_offset(), SXTW)); | 
| +  } | 
| __ Cmp(x10, input_start()); | 
| BranchOrBacktrack(eq, on_at_start); | 
| -  __ Bind(¬_at_start); | 
| } | 
|  | 
|  | 
| -void RegExpMacroAssemblerARM64::CheckNotAtStart(Label* on_not_at_start) { | 
| -  // Did we start the match at the start of the input string? | 
| -  CompareAndBranchOrBacktrack(start_offset(), 0, ne, on_not_at_start); | 
| -  // If we did, are we still at the start of the input string? | 
| +void RegExpMacroAssemblerARM64::CheckNotAtStart(int cp_offset, | 
| +                                                Label* on_not_at_start) { | 
| __ Add(x10, input_end(), Operand(current_input_offset(), SXTW)); | 
| +  __ Add(x10, x10, cp_offset * char_size()); | 
| +  for (int i = 0; i < char_size(); i++) { | 
| +    __ Add(x10, x10, Operand(start_offset(), SXTW)); | 
| +  } | 
| __ Cmp(x10, input_start()); | 
| BranchOrBacktrack(ne, on_not_at_start); | 
| } | 
| @@ -277,9 +277,9 @@ void RegExpMacroAssemblerARM64::CheckGreedyLoop(Label* on_equal) { | 
| BranchOrBacktrack(eq, on_equal); | 
| } | 
|  | 
| + | 
| void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase( | 
| -    int start_reg, | 
| -    Label* on_no_match) { | 
| +    int start_reg, bool read_backward, Label* on_no_match) { | 
| Label fallthrough; | 
|  | 
| Register capture_start_offset = w10; | 
| @@ -297,12 +297,24 @@ void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase( | 
| __ Ldp(w11, capture_start_offset, capture_location(start_reg, x10)); | 
| } | 
| __ Sub(capture_length, w11, capture_start_offset);  // Length to check. | 
| -  // Succeed on empty capture (including no capture). | 
| -  __ Cbz(capture_length, &fallthrough); | 
| + | 
| +  // The length of the capture can only be negative if the end of the | 
| +  // capture is not yet recorded. If the length is zero, the capture is | 
| +  // either empty or uncaptured. In either of those cases, succeed. | 
| +  __ CompareAndBranch(capture_length, Operand(0), le, &fallthrough); | 
|  | 
| // Check that there are enough characters left in the input. | 
| -  __ Cmn(capture_length, current_input_offset()); | 
| -  BranchOrBacktrack(gt, on_no_match); | 
| +  if (read_backward) { | 
| +    __ Add(x12, input_end(), Operand(current_input_offset(), SXTW)); | 
| +    for (int i = 0; i < char_size(); i++) { | 
| +      __ Add(x12, x12, Operand(start_offset(), SXTW)); | 
| +    } | 
| +    __ Cmp(x12, input_start()); | 
| +    BranchOrBacktrack(lt, on_no_match); | 
| +  } else { | 
| +    __ Cmn(capture_length, current_input_offset()); | 
| +    BranchOrBacktrack(gt, on_no_match); | 
| +  } | 
|  | 
| if (mode_ == LATIN1) { | 
| Label success; | 
| @@ -322,6 +334,11 @@ void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase( | 
| __ Add(current_position_address, | 
| input_end(), | 
| Operand(current_input_offset(), SXTW)); | 
| +    if (read_backward) { | 
| +      // Offset by length when matching backwards. | 
| +      __ Sub(current_position_address, current_position_address, | 
| +             Operand(capture_length, SXTW)); | 
| +    } | 
|  | 
| Label loop; | 
| __ Bind(&loop); | 
| @@ -361,6 +378,10 @@ void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase( | 
| // The current input offset should be <= 0, and fit in a W register. | 
| __ Check(le, kOffsetOutOfRange); | 
| } | 
| +    if (read_backward) { | 
| +      __ Sub(current_input_offset(), current_input_offset(), | 
| +             Operand(capture_length, SXTW)); | 
| +    } | 
| } else { | 
| DCHECK(mode_ == UC16); | 
| int argument_count = 4; | 
| @@ -383,6 +404,9 @@ void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase( | 
| __ Mov(w2, capture_length); | 
| // Address of current input position. | 
| __ Add(x1, input_end(), Operand(current_input_offset(), SXTW)); | 
| +    if (read_backward) { | 
| +      __ Sub(x1, x1, Operand(capture_length, SXTW)); | 
| +    } | 
| // Isolate. | 
| __ Mov(x3, ExternalReference::isolate_address(isolate())); | 
|  | 
| @@ -400,16 +424,20 @@ void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase( | 
| __ PopCPURegList(cached_registers); | 
| BranchOrBacktrack(eq, on_no_match); | 
|  | 
| -    // On success, increment position by length of capture. | 
| -    __ Add(current_input_offset(), current_input_offset(), capture_length); | 
| +    // On success, advance position by length of capture. | 
| +    if (read_backward) { | 
| +      __ Sub(current_input_offset(), current_input_offset(), capture_length); | 
| +    } else { | 
| +      __ Add(current_input_offset(), current_input_offset(), capture_length); | 
| +    } | 
| } | 
|  | 
| __ Bind(&fallthrough); | 
| } | 
|  | 
| -void RegExpMacroAssemblerARM64::CheckNotBackReference( | 
| -    int start_reg, | 
| -    Label* on_no_match) { | 
| +void RegExpMacroAssemblerARM64::CheckNotBackReference(int start_reg, | 
| +                                                      bool read_backward, | 
| +                                                      Label* on_no_match) { | 
| Label fallthrough; | 
|  | 
| Register capture_start_address = x12; | 
| @@ -426,12 +454,23 @@ void RegExpMacroAssemblerARM64::CheckNotBackReference( | 
| __ Ldp(w11, w10, capture_location(start_reg, x10)); | 
| } | 
| __ Sub(capture_length, w11, w10);  // Length to check. | 
| -  // Succeed on empty capture (including no capture). | 
| -  __ Cbz(capture_length, &fallthrough); | 
| +  // The length of the capture can only be negative if the end of the | 
| +  // capture is not yet recorded. If the length is zero, the capture is | 
| +  // either empty or uncaptured. In either of those cases, succeed. | 
| +  __ CompareAndBranch(capture_length, Operand(0), le, &fallthrough); | 
|  | 
| // Check that there are enough characters left in the input. | 
| -  __ Cmn(capture_length, current_input_offset()); | 
| -  BranchOrBacktrack(gt, on_no_match); | 
| +  if (read_backward) { | 
| +    __ Add(x12, input_end(), Operand(current_input_offset(), SXTW)); | 
| +    for (int i = 0; i < char_size(); i++) { | 
| +      __ Add(x12, x12, Operand(start_offset(), SXTW)); | 
| +    } | 
| +    __ Cmp(x12, input_start()); | 
| +    BranchOrBacktrack(lt, on_no_match); | 
| +  } else { | 
| +    __ Cmn(capture_length, current_input_offset()); | 
| +    BranchOrBacktrack(gt, on_no_match); | 
| +  } | 
|  | 
| // Compute pointers to match string and capture string | 
| __ Add(capture_start_address, input_end(), Operand(w10, SXTW)); | 
| @@ -441,6 +480,11 @@ void RegExpMacroAssemblerARM64::CheckNotBackReference( | 
| __ Add(current_position_address, | 
| input_end(), | 
| Operand(current_input_offset(), SXTW)); | 
| +  if (read_backward) { | 
| +    // Offset by length when matching backwards. | 
| +    __ Sub(current_position_address, current_position_address, | 
| +           Operand(capture_length, SXTW)); | 
| +  } | 
|  | 
| Label loop; | 
| __ Bind(&loop); | 
| @@ -459,6 +503,11 @@ void RegExpMacroAssemblerARM64::CheckNotBackReference( | 
|  | 
| // Move current character position to position after match. | 
| __ Sub(current_input_offset().X(), current_position_address, input_end()); | 
| +  if (read_backward) { | 
| +    __ Sub(current_input_offset(), current_input_offset(), | 
| +           Operand(capture_length, SXTW)); | 
| +  } | 
| + | 
| if (masm_->emit_debug_code()) { | 
| __ Cmp(current_input_offset().X(), Operand(current_input_offset(), SXTW)); | 
| __ Ccmp(current_input_offset(), 0, NoFlag, eq); | 
| @@ -1081,11 +1130,14 @@ void RegExpMacroAssemblerARM64::LoadCurrentCharacter(int cp_offset, | 
| int characters) { | 
| // TODO(pielan): Make sure long strings are caught before this, and not | 
| // just asserted in debug mode. | 
| -  DCHECK(cp_offset >= -1);      // ^ and \b can look behind one character. | 
| // Be sane! (And ensure that an int32_t can be used to index the string) | 
| DCHECK(cp_offset < (1<<30)); | 
| if (check_bounds) { | 
| -    CheckPosition(cp_offset + characters - 1, on_end_of_input); | 
| +    if (cp_offset >= 0) { | 
| +      CheckPosition(cp_offset + characters - 1, on_end_of_input); | 
| +    } else { | 
| +      CheckPosition(cp_offset, on_end_of_input); | 
| +    } | 
| } | 
| LoadCurrentCharacterUnchecked(cp_offset, characters); | 
| } | 
| @@ -1301,10 +1353,18 @@ int RegExpMacroAssemblerARM64::CheckStackGuardState( | 
|  | 
| void RegExpMacroAssemblerARM64::CheckPosition(int cp_offset, | 
| Label* on_outside_input) { | 
| -  CompareAndBranchOrBacktrack(current_input_offset(), | 
| -                              -cp_offset * char_size(), | 
| -                              ge, | 
| -                              on_outside_input); | 
| +  if (cp_offset >= 0) { | 
| +    CompareAndBranchOrBacktrack(current_input_offset(), | 
| +                                -cp_offset * char_size(), ge, on_outside_input); | 
| +  } else { | 
| +    __ Add(x12, input_end(), Operand(current_input_offset(), SXTW)); | 
| +    __ Add(x12, x12, cp_offset * char_size()); | 
| +    for (int i = 0; i < char_size(); i++) { | 
| +      __ Add(x12, x12, Operand(start_offset(), SXTW)); | 
| +    } | 
| +    __ Cmp(x12, input_start()); | 
| +    BranchOrBacktrack(lt, on_outside_input); | 
| +  } | 
| } | 
|  | 
|  | 
|  |