Clean up regexp code gen a little
authorerik.corry@gmail.com <erik.corry@gmail.com>
Tue, 16 Sep 2014 07:09:39 +0000 (07:09 +0000)
committererik.corry@gmail.com <erik.corry@gmail.com>
Tue, 16 Sep 2014 07:09:39 +0000 (07:09 +0000)
R=yangguo@chromium.org
BUG=

Review URL: https://codereview.chromium.org/565043003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23958 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/jsregexp.cc
src/jsregexp.h

index 0d9f83a..ab2fb08 100644 (file)
@@ -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) {
index 300c0ef..1a97a30 100644 (file)
@@ -590,6 +590,7 @@ class RegExpNode: public ZoneObject {
   // Falls through on certain failure, jumps to the label on possible success.
   // If the node cannot make a quick check it does nothing and returns false.
   bool EmitQuickCheck(RegExpCompiler* compiler,
+                      Trace* bounds_check_trace,
                       Trace* trace,
                       bool preload_has_checked_bounds,
                       Label* on_possible_success,
@@ -1118,7 +1119,6 @@ class ChoiceNode: public RegExpNode {
                    AlternativeGenerationList* alt_gens,
                    int first_choice,
                    Trace* trace,
-                   bool is_greedy_loop,
                    PreloadState* preloads);
   DispatchTable* table_;
   // If true, this node is never checked at the start of the input.