| 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..60950bd1cd86c4dc54171cf503cdb0fe32581ce5 100644 | 
| --- a/src/regexp/arm64/regexp-macro-assembler-arm64.cc | 
| +++ b/src/regexp/arm64/regexp-macro-assembler-arm64.cc | 
| @@ -210,23 +210,17 @@ 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)); | 
| -  __ Cmp(x10, input_start()); | 
| +  __ Add(w10, current_input_offset(), Operand(-char_size())); | 
| +  __ Cmp(w10, string_start_minus_one()); | 
| 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? | 
| -  __ Add(x10, input_end(), Operand(current_input_offset(), SXTW)); | 
| -  __ Cmp(x10, input_start()); | 
| +void RegExpMacroAssemblerARM64::CheckNotAtStart(int cp_offset, | 
| +                                                Label* on_not_at_start) { | 
| +  __ Add(w10, current_input_offset(), | 
| +         Operand(-char_size() + cp_offset * char_size())); | 
| +  __ Cmp(w10, string_start_minus_one()); | 
| BranchOrBacktrack(ne, on_not_at_start); | 
| } | 
|  | 
| @@ -277,9 +271,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 +291,21 @@ 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); | 
| + | 
| +  // At this point, the capture registers are either both set or both cleared. | 
| +  // If the capture length is zero, then the capture is either empty or cleared. | 
| +  // Fall through in both cases. | 
| +  __ CompareAndBranch(capture_length, Operand(0), eq, &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(w12, string_start_minus_one(), capture_length); | 
| +    __ Cmp(current_input_offset(), w12); | 
| +    BranchOrBacktrack(le, on_no_match); | 
| +  } else { | 
| +    __ Cmn(capture_length, current_input_offset()); | 
| +    BranchOrBacktrack(gt, on_no_match); | 
| +  } | 
|  | 
| if (mode_ == LATIN1) { | 
| Label success; | 
| @@ -322,6 +325,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); | 
| @@ -355,6 +363,10 @@ void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase( | 
| __ Bind(&success); | 
| // Compute new value of character position after the matched part. | 
| __ Sub(current_input_offset().X(), current_position_address, input_end()); | 
| +    if (read_backward) { | 
| +      __ Sub(current_input_offset().X(), current_input_offset().X(), | 
| +             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); | 
| @@ -383,6 +395,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 +415,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 +445,21 @@ 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); | 
| + | 
| +  // At this point, the capture registers are either both set or both cleared. | 
| +  // If the capture length is zero, then the capture is either empty or cleared. | 
| +  // Fall through in both cases. | 
| +  __ CompareAndBranch(capture_length, Operand(0), eq, &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(w12, string_start_minus_one(), capture_length); | 
| +    __ Cmp(current_input_offset(), w12); | 
| +    BranchOrBacktrack(le, 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 +469,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 +492,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().X(), current_input_offset().X(), | 
| +           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); | 
| @@ -758,14 +796,13 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) { | 
| // The non-position value is used as a clearing value for the | 
| // capture registers, it corresponds to the position of the first character | 
| // minus one. | 
| -  __ Sub(non_position_value(), current_input_offset(), char_size()); | 
| -  __ Sub(non_position_value(), non_position_value(), | 
| +  __ Sub(string_start_minus_one(), current_input_offset(), char_size()); | 
| +  __ Sub(string_start_minus_one(), string_start_minus_one(), | 
| Operand(start_offset(), LSL, (mode_ == UC16) ? 1 : 0)); | 
| // We can store this value twice in an X register for initializing | 
| // on-stack registers later. | 
| -  __ Orr(twice_non_position_value(), | 
| -         non_position_value().X(), | 
| -         Operand(non_position_value().X(), LSL, kWRegSizeInBits)); | 
| +  __ Orr(twice_non_position_value(), string_start_minus_one().X(), | 
| +         Operand(string_start_minus_one().X(), LSL, kWRegSizeInBits)); | 
|  | 
| // Initialize code pointer register. | 
| __ Mov(code_pointer(), Operand(masm_->CodeObject())); | 
| @@ -1081,11 +1118,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); | 
| } | 
| @@ -1210,7 +1250,7 @@ void RegExpMacroAssemblerARM64::ClearRegisters(int reg_from, int reg_to) { | 
| // If the first capture register is cached in a hardware register but not | 
| // aligned on a 64-bit one, we need to clear the first one specifically. | 
| if ((reg_from < kNumCachedRegisters) && ((reg_from % 2) != 0)) { | 
| -    StoreRegister(reg_from, non_position_value()); | 
| +    StoreRegister(reg_from, string_start_minus_one()); | 
| num_registers--; | 
| reg_from++; | 
| } | 
| @@ -1224,7 +1264,7 @@ void RegExpMacroAssemblerARM64::ClearRegisters(int reg_from, int reg_to) { | 
| } | 
|  | 
| if ((num_registers % 2) == 1) { | 
| -    StoreRegister(reg_from, non_position_value()); | 
| +    StoreRegister(reg_from, string_start_minus_one()); | 
| num_registers--; | 
| reg_from++; | 
| } | 
| @@ -1301,10 +1341,14 @@ 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(w12, current_input_offset(), Operand(cp_offset * char_size())); | 
| +    __ Cmp(w12, string_start_minus_one()); | 
| +    BranchOrBacktrack(le, on_outside_input); | 
| +  } | 
| } | 
|  | 
|  | 
|  |