| Index: src/jsregexp.cc
|
| diff --git a/src/jsregexp.cc b/src/jsregexp.cc
|
| index 0d9f83af37ba48b7ee7b2cf24e81e3ed34d151ab..ab2fb085db94a0c1f54c333bf148f034a742269a 100644
|
| --- a/src/jsregexp.cc
|
| +++ b/src/jsregexp.cc
|
| @@ -2437,6 +2437,7 @@ bool QuickCheckDetails::Rationalize(bool asc) {
|
|
|
|
|
| bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler,
|
| + Trace* bounds_check_trace,
|
| Trace* trace,
|
| bool preload_has_checked_bounds,
|
| Label* on_possible_success,
|
| @@ -2455,8 +2456,13 @@ bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler,
|
| RegExpMacroAssembler* assembler = compiler->macro_assembler();
|
|
|
| if (trace->characters_preloaded() != details->characters()) {
|
| + DCHECK(trace->cp_offset() == bounds_check_trace->cp_offset());
|
| + // We are attempting to preload the minimum number of characters
|
| + // any choice would eat, so if the bounds check fails, then none of the
|
| + // choices can succeed, so we can just immediately backtrack, rather
|
| + // than go to the next choice.
|
| assembler->LoadCurrentCharacter(trace->cp_offset(),
|
| - trace->backtrack(),
|
| + bounds_check_trace->backtrack(),
|
| !preload_has_checked_bounds,
|
| details->characters());
|
| }
|
| @@ -3855,10 +3861,12 @@ void BoyerMooreLookahead::EmitSkipInstructions(RegExpMacroAssembler* masm) {
|
| * \ F V
|
| * \-----S4
|
| *
|
| - * For greedy loops we reverse our expectation and expect to match rather
|
| - * than fail. Therefore we want the loop code to look like this (U is the
|
| - * unwind code that steps back in the greedy loop). The following alternatives
|
| - * look the same as above.
|
| + * For greedy loops we push the current position, then generate the code that
|
| + * eats the input specially in EmitGreedyLoop. The other choice (the
|
| + * continuation) is generated by the normal code in EmitChoices, and steps back
|
| + * in the input to the starting position when it fails to match. The loop code
|
| + * looks like this (U is the unwind code that steps back in the greedy loop).
|
| + *
|
| * _____
|
| * / \
|
| * V |
|
| @@ -3867,20 +3875,14 @@ void BoyerMooreLookahead::EmitSkipInstructions(RegExpMacroAssembler* masm) {
|
| * / |S |
|
| * F/ \_____/
|
| * /
|
| - * |<-----------
|
| - * | \
|
| - * V \
|
| - * Q2 ---> S2 \
|
| - * | S / |
|
| - * F| / |
|
| - * | F/ |
|
| - * | / |
|
| - * | R |
|
| - * | / |
|
| - * F VL |
|
| - * <------U |
|
| - * back |S |
|
| - * \______________/
|
| + * |<-----
|
| + * | \
|
| + * V |S
|
| + * Q2 ---> U----->backtrack
|
| + * | F /
|
| + * S| /
|
| + * V F /
|
| + * S2--/
|
| */
|
|
|
| GreedyLoopState::GreedyLoopState(bool not_at_start) {
|
| @@ -3966,7 +3968,6 @@ void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
|
| &alt_gens,
|
| 0,
|
| trace,
|
| - false, // Not greedy loop.
|
| &preload);
|
| }
|
|
|
| @@ -3974,7 +3975,7 @@ void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
|
| // the quick check was inlined. We can recognize these because the associated
|
| // label was bound.
|
| int new_flush_budget = trace->flush_budget() / choice_count;
|
| - for (int i = 0; i < choice_count - 1; i++) {
|
| + for (int i = 0; i < choice_count; i++) {
|
| AlternativeGeneration* alt_gen = alt_gens.at(i);
|
| Trace new_trace(*trace);
|
| // If there are actions to be flushed we have to limit how many times
|
| @@ -3983,12 +3984,14 @@ void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
|
| if (new_trace.actions() != NULL) {
|
| new_trace.set_flush_budget(new_flush_budget);
|
| }
|
| + bool next_expects_preload =
|
| + i == choice_count - 1 ? false : alt_gens.at(i + 1)->expects_preload;
|
| EmitOutOfLineContinuation(compiler,
|
| &new_trace,
|
| alternatives_->at(i),
|
| alt_gen,
|
| preload.preload_characters_,
|
| - alt_gens.at(i + 1)->expects_preload);
|
| + next_expects_preload);
|
| }
|
| }
|
|
|
| @@ -4029,7 +4032,6 @@ Trace* ChoiceNode::EmitGreedyLoop(RegExpCompiler* compiler,
|
| alt_gens,
|
| 1,
|
| new_trace,
|
| - true, // Is greedy loop.
|
| preload);
|
|
|
| macro_assembler->Bind(greedy_loop_state->label());
|
| @@ -4096,7 +4098,6 @@ void ChoiceNode::EmitChoices(RegExpCompiler* compiler,
|
| AlternativeGenerationList* alt_gens,
|
| int first_choice,
|
| Trace* trace,
|
| - bool is_greedy_loop,
|
| PreloadState* preload) {
|
| RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
|
| SetUpPreLoad(compiler, trace, preload);
|
| @@ -4109,6 +4110,7 @@ void ChoiceNode::EmitChoices(RegExpCompiler* compiler,
|
|
|
| for (int i = first_choice; i < choice_count; i++) {
|
| bool is_last = i == choice_count - 1;
|
| + bool fall_through_on_failure = !is_last;
|
| GuardedAlternative alternative = alternatives_->at(i);
|
| AlternativeGeneration* alt_gen = alt_gens->at(i);
|
| alt_gen->quick_check_details.set_characters(preload->preload_characters_);
|
| @@ -4123,23 +4125,26 @@ void ChoiceNode::EmitChoices(RegExpCompiler* compiler,
|
| }
|
| new_trace.quick_check_performed()->Clear();
|
| if (not_at_start_) new_trace.set_at_start(Trace::FALSE_VALUE);
|
| + if (!is_last) {
|
| + new_trace.set_backtrack(&alt_gen->after);
|
| + }
|
| alt_gen->expects_preload = preload->preload_is_current_;
|
| bool generate_full_check_inline = false;
|
| if (FLAG_regexp_optimization &&
|
| try_to_emit_quick_check_for_alternative(i == 0) &&
|
| alternative.node()->EmitQuickCheck(compiler,
|
| + trace,
|
| &new_trace,
|
| preload->preload_has_checked_bounds_,
|
| &alt_gen->possible_success,
|
| &alt_gen->quick_check_details,
|
| - !is_last)) {
|
| + fall_through_on_failure)) {
|
| // Quick check was generated for this choice.
|
| preload->preload_is_current_ = true;
|
| preload->preload_has_checked_bounds_ = true;
|
| - // On the last choice in the ChoiceNode we generated the quick
|
| - // check to fall through on possible success. So now we need to
|
| - // generate the full check inline.
|
| - if (is_last) {
|
| + // If we generated the quick check to fall through on possible success,
|
| + // we now need to generate the full check inline.
|
| + if (!fall_through_on_failure) {
|
| macro_assembler->Bind(&alt_gen->possible_success);
|
| new_trace.set_quick_check_performed(&alt_gen->quick_check_details);
|
| new_trace.set_characters_preloaded(preload->preload_characters_);
|
| @@ -4147,9 +4152,9 @@ void ChoiceNode::EmitChoices(RegExpCompiler* compiler,
|
| generate_full_check_inline = true;
|
| }
|
| } else if (alt_gen->quick_check_details.cannot_match()) {
|
| - if (is_last && !is_greedy_loop) {
|
| + if (!fall_through_on_failure) {
|
| macro_assembler->GoTo(trace->backtrack());
|
| - } // Else just fall through to the next test.
|
| + }
|
| continue;
|
| } else {
|
| // No quick check was generated. Put the full code here.
|
| @@ -4161,9 +4166,6 @@ void ChoiceNode::EmitChoices(RegExpCompiler* compiler,
|
| alt_gen->expects_preload = false;
|
| new_trace.InvalidateCurrentCharacter();
|
| }
|
| - if (!is_last) {
|
| - new_trace.set_backtrack(&alt_gen->after);
|
| - }
|
| generate_full_check_inline = true;
|
| }
|
| if (generate_full_check_inline) {
|
|
|