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) { |