Irregexp:
authorerik.corry@gmail.com <erik.corry@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 8 Dec 2008 09:22:12 +0000 (09:22 +0000)
committererik.corry@gmail.com <erik.corry@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 8 Dec 2008 09:22:12 +0000 (09:22 +0000)
* Facility for generating a node several ways.  This allows
  code to be generated for a node knowing where it is trying
  to match relative to the 'current position' and it allows
  code to be generated that knows where to backtrack to.  Both
  allow dramatic reductions in the amount of popping and pushing
  on the stack and the number of indirect jumps.
* Generate special backtracking for greedy quantifiers on
  constant-length atoms.  This allows .* to run in constant
  space relative to input string size.
* When we are checking a long sequence of characters or character
  classes in the input then we do them right to left and only the
  first (rightmost) needs to check for end-of-string.
* Record the pattern in the profile instead of just <CompiledRegExp>
* Nodes no longer contain an on_failure_ node.  This was only used
  for lookaheads and they are now handled with a choice node instead.
Review URL: http://codereview.chromium.org/12900

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

15 files changed:
src/ast.h
src/bytecodes-irregexp.h
src/interpreter-irregexp.cc
src/jsregexp-inl.h
src/jsregexp.cc
src/jsregexp.h
src/regexp-macro-assembler-ia32.cc
src/regexp-macro-assembler-ia32.h
src/regexp-macro-assembler-irregexp.cc
src/regexp-macro-assembler-irregexp.h
src/regexp-macro-assembler-tracer.cc
src/regexp-macro-assembler-tracer.h
src/regexp-macro-assembler.h
test/cctest/test-regexp.cc
test/mjsunit/regexp.js

index a301ab7..528c4f5 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -1216,8 +1216,7 @@ class RegExpTree: public ZoneObject {
   virtual ~RegExpTree() { }
   virtual void* Accept(RegExpVisitor* visitor, void* data) = 0;
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
-                             RegExpNode* on_success,
-                             RegExpNode* on_failure) = 0;
+                             RegExpNode* on_success) = 0;
   virtual bool IsTextElement() { return false; }
   virtual void AppendToText(RegExpText* text);
   SmartPointer<const char> ToString();
@@ -1235,8 +1234,7 @@ class RegExpDisjunction: public RegExpTree {
       : alternatives_(alternatives) { }
   virtual void* Accept(RegExpVisitor* visitor, void* data);
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
-                             RegExpNode* on_success,
-                             RegExpNode* on_failure);
+                             RegExpNode* on_success);
   virtual RegExpDisjunction* AsDisjunction();
   virtual bool IsDisjunction();
   ZoneList<RegExpTree*>* alternatives() { return alternatives_; }
@@ -1250,8 +1248,7 @@ class RegExpAlternative: public RegExpTree {
   explicit RegExpAlternative(ZoneList<RegExpTree*>* nodes) : nodes_(nodes) { }
   virtual void* Accept(RegExpVisitor* visitor, void* data);
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
-                             RegExpNode* on_success,
-                             RegExpNode* on_failure);
+                             RegExpNode* on_success);
   virtual RegExpAlternative* AsAlternative();
   virtual bool IsAlternative();
   ZoneList<RegExpTree*>* nodes() { return nodes_; }
@@ -1265,8 +1262,7 @@ class RegExpText: public RegExpTree {
   RegExpText() : elements_(2) { }
   virtual void* Accept(RegExpVisitor* visitor, void* data);
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
-                             RegExpNode* on_success,
-                             RegExpNode* on_failure);
+                             RegExpNode* on_success);
   virtual RegExpText* AsText();
   virtual bool IsText();
   virtual bool IsTextElement() { return true; }
@@ -1291,8 +1287,7 @@ class RegExpAssertion: public RegExpTree {
   explicit RegExpAssertion(Type type) : type_(type) { }
   virtual void* Accept(RegExpVisitor* visitor, void* data);
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
-                             RegExpNode* on_success,
-                             RegExpNode* on_failure);
+                             RegExpNode* on_success);
   virtual RegExpAssertion* AsAssertion();
   virtual bool IsAssertion();
   Type type() { return type_; }
@@ -1313,8 +1308,7 @@ class RegExpCharacterClass: public RegExpTree {
   }
   virtual void* Accept(RegExpVisitor* visitor, void* data);
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
-                             RegExpNode* on_success,
-                             RegExpNode* on_failure);
+                             RegExpNode* on_success);
   virtual RegExpCharacterClass* AsCharacterClass();
   virtual bool IsCharacterClass();
   virtual bool IsTextElement() { return true; }
@@ -1332,8 +1326,7 @@ class RegExpAtom: public RegExpTree {
   explicit RegExpAtom(Vector<const uc16> data) : data_(data) { }
   virtual void* Accept(RegExpVisitor* visitor, void* data);
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
-                             RegExpNode* on_success,
-                             RegExpNode* on_failure);
+                             RegExpNode* on_success);
   virtual RegExpAtom* AsAtom();
   virtual bool IsAtom();
   virtual bool IsTextElement() { return true; }
@@ -1353,15 +1346,13 @@ class RegExpQuantifier: public RegExpTree {
         body_(body) { }
   virtual void* Accept(RegExpVisitor* visitor, void* data);
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
-                             RegExpNode* on_success,
-                             RegExpNode* on_failure);
+                             RegExpNode* on_success);
   static RegExpNode* ToNode(int min,
                             int max,
                             bool is_greedy,
                             RegExpTree* body,
                             RegExpCompiler* compiler,
-                            RegExpNode* on_success,
-                            RegExpNode* on_failure);
+                            RegExpNode* on_success);
   virtual RegExpQuantifier* AsQuantifier();
   virtual bool IsQuantifier();
   int min() { return min_; }
@@ -1391,13 +1382,11 @@ class RegExpCapture: public RegExpTree {
       : body_(body), index_(index), available_(CAPTURE_AVAILABLE) { }
   virtual void* Accept(RegExpVisitor* visitor, void* data);
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
-                             RegExpNode* on_success,
-                             RegExpNode* on_failure);
+                             RegExpNode* on_success);
   static RegExpNode* ToNode(RegExpTree* body,
                             int index,
                             RegExpCompiler* compiler,
-                            RegExpNode* on_success,
-                            RegExpNode* on_failure);
+                            RegExpNode* on_success);
   virtual RegExpCapture* AsCapture();
   virtual bool IsCapture();
   RegExpTree* body() { return body_; }
@@ -1422,8 +1411,7 @@ class RegExpLookahead: public RegExpTree {
         is_positive_(is_positive) { }
   virtual void* Accept(RegExpVisitor* visitor, void* data);
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
-                             RegExpNode* on_success,
-                             RegExpNode* on_failure);
+                             RegExpNode* on_success);
   virtual RegExpLookahead* AsLookahead();
   virtual bool IsLookahead();
   RegExpTree* body() { return body_; }
@@ -1440,8 +1428,7 @@ class RegExpBackReference: public RegExpTree {
       : capture_(capture) { }
   virtual void* Accept(RegExpVisitor* visitor, void* data);
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
-                             RegExpNode* on_success,
-                             RegExpNode* on_failure);
+                             RegExpNode* on_success);
   virtual RegExpBackReference* AsBackReference();
   virtual bool IsBackReference();
   int index() { return capture_->index(); }
@@ -1456,8 +1443,7 @@ class RegExpEmpty: public RegExpTree {
   RegExpEmpty() { }
   virtual void* Accept(RegExpVisitor* visitor, void* data);
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
-                             RegExpNode* on_success,
-                             RegExpNode* on_failure);
+                             RegExpNode* on_success);
   virtual RegExpEmpty* AsEmpty();
   virtual bool IsEmpty();
   static RegExpEmpty* GetInstance() { return &kInstance; }
index 33a2f24..64a65cb 100644 (file)
@@ -50,22 +50,24 @@ V(SUCCEED,           14, 1) /* succeed                                      */ \
 V(ADVANCE_CP,        15, 5) /* advance_cp offset32                          */ \
 V(GOTO,              16, 5) /* goto addr32                                  */ \
 V(LOAD_CURRENT_CHAR, 17, 9) /* load offset32 addr32                         */ \
-V(CHECK_CHAR,        18, 7) /* check_char uc16 addr32                       */ \
-V(CHECK_NOT_CHAR,    19, 7) /* check_not_char uc16 addr32                   */ \
-V(OR_CHECK_NOT_CHAR, 20, 9) /* or_check_not_char uc16 uc16 addr32           */ \
-V(MINUS_OR_CHECK_NOT_CHAR, 21, 9) /* minus_or_check_not_char uc16 uc16 ad...*/ \
-V(CHECK_LT,          22, 7) /* check_lt uc16 addr32                         */ \
-V(CHECK_GT,          23, 7) /* check_gr uc16 addr32                         */ \
-V(CHECK_NOT_BACK_REF, 24, 6) /* check_not_back_ref capture_idx addr32       */ \
-V(CHECK_NOT_BACK_REF_NO_CASE, 25, 6) /* check_not_back_ref_no_case captu... */ \
-V(CHECK_NOT_REGS_EQUAL, 26, 7) /* check_not_regs_equal reg1 reg2 addr32     */ \
-V(LOOKUP_MAP1,       27, 11) /* l_map1 start16 bit_map_addr32 addr32        */ \
-V(LOOKUP_MAP2,       28, 99) /* l_map2 start16 half_nibble_map_addr32*      */ \
-V(LOOKUP_MAP8,       29, 99) /* l_map8 start16 byte_map addr32*             */ \
-V(LOOKUP_HI_MAP8,    30, 99) /* l_himap8 start8 byte_map_addr32 addr32*     */ \
-V(CHECK_REGISTER_LT, 31, 8) /* check_reg_lt register_index value16 addr32   */ \
-V(CHECK_REGISTER_GE, 32, 8) /* check_reg_ge register_index value16 addr32   */ \
-V(CHECK_NOT_AT_START, 33, 5) /* check_not_at_start addr32                   */
+V(LOAD_CURRENT_CHAR_UNCHECKED, 18, 5) /* load offset32                      */ \
+V(CHECK_CHAR,        19, 7) /* check_char uc16 addr32                       */ \
+V(CHECK_NOT_CHAR,    20, 7) /* check_not_char uc16 addr32                   */ \
+V(OR_CHECK_NOT_CHAR, 21, 9) /* or_check_not_char uc16 uc16 addr32           */ \
+V(MINUS_OR_CHECK_NOT_CHAR, 22, 9) /* minus_or_check_not_char uc16 uc16 ad...*/ \
+V(CHECK_LT,          23, 7) /* check_lt uc16 addr32                         */ \
+V(CHECK_GT,          24, 7) /* check_gr uc16 addr32                         */ \
+V(CHECK_NOT_BACK_REF, 25, 6) /* check_not_back_ref capture_idx addr32       */ \
+V(CHECK_NOT_BACK_REF_NO_CASE, 26, 6) /* check_not_back_ref_no_case captu... */ \
+V(CHECK_NOT_REGS_EQUAL, 27, 7) /* check_not_regs_equal reg1 reg2 addr32     */ \
+V(LOOKUP_MAP1,       28, 11) /* l_map1 start16 bit_map_addr32 addr32        */ \
+V(LOOKUP_MAP2,       29, 99) /* l_map2 start16 half_nibble_map_addr32*      */ \
+V(LOOKUP_MAP8,       30, 99) /* l_map8 start16 byte_map addr32*             */ \
+V(LOOKUP_HI_MAP8,    31, 99) /* l_himap8 start8 byte_map_addr32 addr32*     */ \
+V(CHECK_REGISTER_LT, 32, 8) /* check_reg_lt register_index value16 addr32   */ \
+V(CHECK_REGISTER_GE, 33, 8) /* check_reg_ge register_index value16 addr32   */ \
+V(CHECK_NOT_AT_START, 34, 5) /* check_not_at_start addr32                   */ \
+V(CHECK_GREEDY,      35, 5) /* check_greedy addr32                          */
 
 #define DECLARE_BYTECODES(name, code, length) \
   static const int BC_##name = code;
index f76c135..afc58ca 100644 (file)
@@ -191,6 +191,15 @@ static bool RawMatch(const byte* code_base,
       BYTECODE(GOTO)
         pc = code_base + Load32(pc + 1);
         break;
+      BYTECODE(CHECK_GREEDY)
+        if (current == backtrack_sp[-1]) {
+          backtrack_sp--;
+          backtrack_stack_space++;
+          pc = code_base + Load32(pc + 1);
+        } else {
+          pc += BC_CHECK_GREEDY_LENGTH;
+        }
+        break;
       BYTECODE(LOAD_CURRENT_CHAR) {
         int pos = current + Load32(pc + 1);
         if (pos >= subject.length()) {
@@ -201,6 +210,12 @@ static bool RawMatch(const byte* code_base,
         }
         break;
       }
+      BYTECODE(LOAD_CURRENT_CHAR_UNCHECKED) {
+        int pos = current + Load32(pc + 1);
+        current_char = subject[pos];
+        pc += BC_LOAD_CURRENT_CHAR_UNCHECKED_LENGTH;
+        break;
+      }
       BYTECODE(CHECK_CHAR) {
         int c = Load16(pc + 1);
         if (c == current_char) {
index 9371703..09c4c8f 100644 (file)
@@ -253,11 +253,6 @@ static void DoForEach(Node* node, Callback* callback) {
 }
 
 
-void RegExpNode::Bind(RegExpMacroAssembler* macro) {
-  macro->Bind(&label_);
-}
-
-
 }}  // namespace v8::internal
 
 
index 3046b96..d289eaa 100644 (file)
@@ -242,7 +242,8 @@ Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
           RegExpEngine::Compile(&parse_result,
                                 &node,
                                 flags.is_ignore_case(),
-                                flags.is_multiline());
+                                flags.is_multiline(),
+                                pattern);
       if (irregexp_data.is_null()) {
         if (FLAG_disable_jscre) {
           UNIMPLEMENTED();
@@ -858,6 +859,154 @@ Handle<ByteArray> RegExpImpl::IrregexpCode(Handle<JSRegExp> re) {
 
 // -------------------------------------------------------------------
 // Implmentation of the Irregexp regular expression engine.
+//
+// The Irregexp regular expression engine is intended to be a complete
+// implementation of ECMAScript regular expressions.  It generates either
+// bytecodes or native code.
+
+//   The Irregexp regexp engine is structured in three steps.
+//   1) The parser generates an abstract syntax tree.  See ast.cc.
+//   2) From the AST a node network is created.  The nodes are all
+//      subclasses of RegExpNode.  The nodes represent states when
+//      executing a regular expression.  Several optimizations are
+//      performed on the node network.
+//   3) From the nodes we generate either byte codes or native code
+//      that can actually execute the regular expression (perform
+//      the search).  The code generation step is described in more
+//      detail below.
+
+// Code generation.
+//
+//   The nodes are divided into four main categories.
+//   * Choice nodes
+//        These represent places where the regular expression can
+//        match in more than one way.  For example on entry to an
+//        alternation (foo|bar) or a repetition (*, +, ? or {}).
+//   * Action nodes
+//        These represent places where some action should be
+//        performed.  Examples include recording the current position
+//        in the input string to a register (in order to implement
+//        captures) or other actions on register for example in order
+//        to implement the counters needed for {} repetitions.
+//   * Matching nodes
+//        These attempt to match some element part of the input string.
+//        Examples of elements include character classes, plain strings
+//        or back references.
+//   * End nodes
+//        These are used to implement the actions required on finding
+//        a successful match or failing to find a match.
+//
+//   The code generated (whether as byte codes or native code) maintains
+//   some state as it runs.  This consists of the following elements:
+//
+//   * The capture registers.  Used for string captures.
+//   * Other registers.  Used for counters etc.
+//   * The current position.
+//   * The stack of backtracking information.  Used when a matching node
+//     fails to find a match and needs to try an alternative.
+//
+// Conceptual regular expression execution model:
+//
+//   There is a simple conceptual model of regular expression execution
+//   which will be presented first.  The actual code generated is a more
+//   efficient simulation of the simple conceptual model:
+//
+//   * Choice nodes are implemented as follows:
+//     For each choice except the last {
+//       push current position
+//       push backtrack code location
+//       <generate code to test for choice>
+//       backtrack code location:
+//       pop current position
+//     }
+//     <generate code to test for last choice>
+//
+//   * Actions nodes are generated as follows
+//     <push affected registers on backtrack stack>
+//     <generate code to perform action>
+//     push backtrack code location
+//     <generate code to test for following nodes>
+//     backtrack code location:
+//     <pop affected registers to restore their state>
+//     <pop backtrack location from stack and go to it>
+//
+//   * Matching nodes are generated as follows:
+//     if input string matches at current position
+//       update current position
+//       <generate code to test for following nodes>
+//     else
+//       <pop backtrack location from stack and go to it>
+//
+//   Thus it can be seen that the current position is saved and restored
+//   by the choice nodes, whereas the registers are saved and restored by
+//   by the action nodes that manipulate them.
+//
+//   The other interesting aspect of this model is that nodes are generated
+//   at the point where they are needed by a recursive call to Emit().  If
+//   the node has already been code generated then the Emit() call will
+//   generate a jump to the previously generated code instead.  In order to
+//   limit recursion it is possible for the Emit() function to put the node
+//   on a work list for later generation and instead generate a jump.  The
+//   destination of the jump is resolved later when the code is generated.
+//
+// Actual regular expression code generation.
+//
+//   Code generation is actually more complicated than the above.  In order
+//   to improve the efficiency of the generated code some optimizations are
+//   performed
+//
+//   * Choice nodes have 1-character lookahead.
+//     A choice node looks at the following character and eliminates some of
+//     the choices immediately based on that character.  This is not yet
+//     implemented.
+//   * Simple greedy loops store reduced backtracking information.
+//     A quantifier like /.*foo/m will greedily match the whole input.  It will
+//     then need to backtrack to a point where it can match "foo".  The naive
+//     implementation of this would push each character position onto the
+//     backtracking stack, then pop them off one by one.  This would use space
+//     proportional to the length of the input string.  However since the "."
+//     can only match in one way and always has a constant length (in this case
+//     of 1) it suffices to store the current position on the top of the stack
+//     once.  Matching now becomes merely incrementing the current position and
+//     backtracking becomes decrementing the current position and checking the
+//     result against the stored current position.  This is faster and saves
+//     space.
+//   * The current state is virtualized.
+//     This is used to defer expensive operations until it is clear that they
+//     are needed and to generate code for a node more than once, allowing
+//     specialized an efficient versions of the code to be created. This is
+//     explained in the section below.
+//
+// Execution state virtualization.
+//
+//   Instead of emitting code, nodes that manipulate the state can record their
+//   manipulation in an object called the GenerationVariant.  The
+//   GenerationVariant object can record a current position offset, an
+//   optional backtrack code location on the top of the virtualized backtrack
+//   stack and some register changes.  When a node is to be emitted it can flush
+//   the GenerationVariant or update it.  Flushing the GenerationVariant
+//   will emit code to bring the actual state into line with the virtual state.
+//   Avoiding flushing the state can postpone some work (eg updates of capture
+//   registers).  Postponing work can save time when executing the regular
+//   expression since it may be found that the work never has to be done as a
+//   failure to match can occur.  In addition it is much faster to jump to a
+//   known backtrack code location than it is to pop an unknown backtrack
+//   location from the stack and jump there.
+//
+//   The virtual state found in the GenerationVariant affects code generation.
+//   For example the virtual state contains the difference between the actual
+//   current position and the virtual current position, and matching code needs
+//   to use this offset to attempt a match in the correct location of the input
+//   string.  Therefore code generated for a non-trivial GenerationVariant is
+//   specialized to that GenerationVariant.  The code generator therefore
+//   has the ability to generate code for each node several times.  In order to
+//   limit the size of the generated code there is an arbitrary limit on how
+//   many specialized sets of code may be generated for a given node.  If the
+//   limit is reached, the GenerationVariant is flushed and a generic version of
+//   the code for a node is emitted.  This is subsequently used for that node.
+//   The code emitted for non-generic GenerationVariants is not recorded in the
+//   node and so it cannot currently be reused in the event that code generation
+//   is requested for an identical GenerationVariant.
 
 
 void RegExpTree::AppendToText(RegExpText* text) {
@@ -914,7 +1063,8 @@ class RegExpCompiler {
 
   Handle<FixedArray> Assemble(RegExpMacroAssembler* assembler,
                               RegExpNode* start,
-                              int capture_count);
+                              int capture_count,
+                              Handle<String> pattern);
 
   inline void AddWork(RegExpNode* node) { work_list_->Add(node); }
 
@@ -924,7 +1074,6 @@ class RegExpCompiler {
 
   RegExpMacroAssembler* macro_assembler() { return macro_assembler_; }
   EndNode* accept() { return accept_; }
-  EndNode* backtrack() { return backtrack_; }
 
   static const int kMaxRecursion = 100;
   inline int recursion_depth() { return recursion_depth_; }
@@ -935,7 +1084,6 @@ class RegExpCompiler {
 
  private:
   EndNode* accept_;
-  EndNode* backtrack_;
   int next_register_;
   List<RegExpNode*>* work_list_;
   int recursion_depth_;
@@ -944,6 +1092,17 @@ class RegExpCompiler {
 };
 
 
+class RecursionCheck {
+ public:
+  explicit RecursionCheck(RegExpCompiler* compiler) : compiler_(compiler) {
+    compiler->IncrementRecursionDepth();
+  }
+  ~RecursionCheck() { compiler_->DecrementRecursionDepth(); }
+ private:
+  RegExpCompiler* compiler_;
+};
+
+
 // Attempts to compile the regexp using an Irregexp code generator.  Returns
 // a fixed array or a null handle depending on whether it succeeded.
 RegExpCompiler::RegExpCompiler(int capture_count, bool ignore_case)
@@ -952,14 +1111,14 @@ RegExpCompiler::RegExpCompiler(int capture_count, bool ignore_case)
       recursion_depth_(0),
       ignore_case_(ignore_case) {
   accept_ = new EndNode(EndNode::ACCEPT);
-  backtrack_ = new EndNode(EndNode::BACKTRACK);
 }
 
 
 Handle<FixedArray> RegExpCompiler::Assemble(
     RegExpMacroAssembler* macro_assembler,
     RegExpNode* start,
-    int capture_count) {
+    int capture_count,
+    Handle<String> pattern) {
 #ifdef DEBUG
   if (FLAG_trace_regexp_assembler)
     macro_assembler_ = new RegExpMacroAssemblerTracer(macro_assembler);
@@ -969,19 +1128,19 @@ Handle<FixedArray> RegExpCompiler::Assemble(
   List <RegExpNode*> work_list(0);
   work_list_ = &work_list;
   Label fail;
-  macro_assembler_->PushBacktrack(&fail);
-  if (!start->GoTo(this)) {
+  macro_assembler->PushBacktrack(&fail);
+  GenerationVariant generic_variant;
+  if (!start->Emit(this, &generic_variant)) {
     fail.Unuse();
     return Handle<FixedArray>::null();
   }
+  macro_assembler_->Bind(&fail);
+  macro_assembler_->Fail();
   while (!work_list.is_empty()) {
-    if (!work_list.RemoveLast()->GoTo(this)) {
-      fail.Unuse();
+    if (!work_list.RemoveLast()->Emit(this, &generic_variant)) {
       return Handle<FixedArray>::null();
     }
   }
-  macro_assembler_->Bind(&fail);
-  macro_assembler_->Fail();
   Handle<FixedArray> array =
       Factory::NewFixedArray(RegExpImpl::kIrregexpDataLength);
   array->set(RegExpImpl::kIrregexpImplementationIndex,
@@ -990,7 +1149,7 @@ Handle<FixedArray> RegExpCompiler::Assemble(
              Smi::FromInt(next_register_));
   array->set(RegExpImpl::kIrregexpNumberOfCapturesIndex,
              Smi::FromInt(capture_count));
-  Handle<Object> code = macro_assembler_->GetCode();
+  Handle<Object> code = macro_assembler_->GetCode(pattern);
   array->set(RegExpImpl::kIrregexpCodeIndex, *code);
   work_list_ = NULL;
 #ifdef DEBUG
@@ -1002,71 +1161,217 @@ Handle<FixedArray> RegExpCompiler::Assemble(
 }
 
 
-bool RegExpNode::GoTo(RegExpCompiler* compiler) {
-  // TODO(erikcorry): Implement support.
-  if (info_.follows_word_interest ||
-      info_.follows_newline_interest ||
-      info_.follows_start_interest) {
-    return false;
+bool GenerationVariant::mentions_reg(int reg) {
+  for (DeferredAction* action = actions_;
+       action != NULL;
+       action = action->next()) {
+    if (reg == action->reg()) return true;
   }
-  if (label_.is_bound()) {
-    compiler->macro_assembler()->GoTo(&label_);
-    return true;
-  } else {
-    if (compiler->recursion_depth() > RegExpCompiler::kMaxRecursion) {
-      compiler->macro_assembler()->GoTo(&label_);
-      compiler->AddWork(this);
-      return true;
+  return false;
+}
+
+
+int GenerationVariant::FindAffectedRegisters(OutSet* affected_registers) {
+  int max_register = -1;
+  for (DeferredAction* action = actions_;
+       action != NULL;
+       action = action->next()) {
+    affected_registers->Set(action->reg());
+    if (action->reg() > max_register) max_register = action->reg();
+  }
+  return max_register;
+}
+
+
+void GenerationVariant::PushAffectedRegisters(RegExpMacroAssembler* macro,
+                                              int max_register,
+                                              OutSet& affected_registers) {
+  for (int reg = 0; reg <= max_register; reg++) {
+    if (affected_registers.Get(reg)) macro->PushRegister(reg);
+  }
+}
+
+
+void GenerationVariant::RestoreAffectedRegisters(RegExpMacroAssembler* macro,
+                                                 int max_register,
+                                                 OutSet& affected_registers) {
+  for (int reg = max_register; reg >= 0; reg--) {
+    if (affected_registers.Get(reg)) macro->PopRegister(reg);
+  }
+}
+
+
+void GenerationVariant::PerformDeferredActions(RegExpMacroAssembler* macro,
+                                               int max_register,
+                                               OutSet& affected_registers) {
+  for (int reg = 0; reg <= max_register; reg++) {
+    if (!affected_registers.Get(reg)) {
+      continue;
+    }
+    int value = 0;
+    bool absolute = false;
+    int store_position = -1;
+    // This is a little tricky because we are scanning the actions in reverse
+    // historical order (newest first).
+    for (DeferredAction* action = actions_;
+         action != NULL;
+         action = action->next()) {
+      if (action->reg() == reg) {
+        switch (action->type()) {
+          case ActionNode::SET_REGISTER: {
+            GenerationVariant::DeferredSetRegister* psr =
+                static_cast<GenerationVariant::DeferredSetRegister*>(action);
+            value += psr->value();
+            absolute = true;
+            ASSERT_EQ(store_position, -1);
+            break;
+          }
+          case ActionNode::INCREMENT_REGISTER:
+            if (!absolute) {
+              value++;
+            }
+            ASSERT_EQ(store_position, -1);
+            break;
+          case ActionNode::STORE_POSITION: {
+            GenerationVariant::DeferredCapture* pc =
+                static_cast<GenerationVariant::DeferredCapture*>(action);
+            if (store_position == -1) {
+              store_position = pc->cp_offset();
+            }
+            ASSERT(!absolute);
+            ASSERT_EQ(value, 0);
+            break;
+          }
+          default:
+            UNREACHABLE();
+            break;
+        }
+      }
+    }
+    if (store_position != -1) {
+      macro->WriteCurrentPositionToRegister(reg, store_position);
     } else {
-      compiler->IncrementRecursionDepth();
-      bool how_it_went = Emit(compiler);
-      compiler->DecrementRecursionDepth();
-      return how_it_went;
+      if (absolute) {
+        macro->SetRegister(reg, value);
+      } else {
+        if (value != 0) {
+          macro->AdvanceRegister(reg, value);
+        }
+      }
     }
   }
 }
 
 
-// EndNodes are special.  Because they can be very common and they are very
-// short we normally inline them.  That is, if we are asked to emit a GoTo
-// we just emit the entire node.  Since they don't have successors this
-// works.
-bool EndNode::GoTo(RegExpCompiler* compiler) {
-  if (info()->follows_word_interest ||
-      info()->follows_newline_interest ||
-      info()->follows_start_interest) {
-    return false;
+// This is called as we come into a loop choice node and some other tricky
+// nodes.  It normalises the state of the code generator to ensure we can
+// generate generic code.
+bool GenerationVariant::Flush(RegExpCompiler* compiler, RegExpNode* successor) {
+  RegExpMacroAssembler* macro = compiler->macro_assembler();
+
+  ASSERT(actions_ != NULL || cp_offset_ != 0 || backtrack() != NULL);
+
+  if (actions_ == NULL && backtrack() == NULL) {
+    // Here we just have some deferred cp advances to fix and we are back to
+    // a normal situation.
+    macro->AdvanceCurrentPosition(cp_offset_);
+    // Create a new trivial state and generate the node with that.
+    GenerationVariant new_state;
+    return successor->Emit(compiler, &new_state);
+  }
+
+  // Generate deferred actions here along with code to undo them again.
+  OutSet affected_registers;
+  int max_register = FindAffectedRegisters(&affected_registers);
+  PushAffectedRegisters(macro, max_register, affected_registers);
+  PerformDeferredActions(macro, max_register, affected_registers);
+  if (backtrack() != NULL) {
+    // Here we have a concrete backtrack location.  These are set up by choice
+    // nodes and so they indicate that we have a deferred save of the current
+    // position which we may need to emit here.
+    macro->PushCurrentPosition();
+  }
+  if (cp_offset_ != 0) {
+    macro->AdvanceCurrentPosition(cp_offset_);
+  }
+
+  // Create a new trivial state and generate the node with that.
+  Label undo;
+  macro->PushBacktrack(&undo);
+  GenerationVariant new_state;
+  bool ok = successor->Emit(compiler, &new_state);
+
+  // On backtrack we need to restore state.
+  macro->Bind(&undo);
+  if (!ok) return false;
+  if (backtrack() != NULL) {
+    macro->PopCurrentPosition();
+  }
+  RestoreAffectedRegisters(macro, max_register, affected_registers);
+  if (backtrack() == NULL) {
+    macro->Backtrack();
+  } else {
+    macro->GoTo(backtrack());
+  }
+
+  return true;
+}
+
+
+void EndNode::EmitInfoChecks(RegExpMacroAssembler* macro,
+                             GenerationVariant* variant) {
+  if (info()->at_end) {
+    Label succeed;
+    // LoadCurrentCharacter will go to the label if we are at the end of the
+    // input string.
+    macro->LoadCurrentCharacter(0, &succeed);
+    macro->GoTo(variant->backtrack());
+    macro->Bind(&succeed);
   }
-  return Emit(compiler);
 }
 
 
-Label* RegExpNode::label() {
-  return &label_;
+bool NegativeSubmatchSuccess::Emit(RegExpCompiler* compiler,
+                                   GenerationVariant* variant) {
+  if (!variant->is_trivial()) {
+    return variant->Flush(compiler, this);
+  }
+  RegExpMacroAssembler* macro = compiler->macro_assembler();
+  if (!label()->is_bound()) {
+    macro->Bind(label());
+  }
+  EmitInfoChecks(macro, variant);
+  macro->ReadCurrentPositionFromRegister(current_position_register_);
+  macro->ReadStackPointerFromRegister(stack_pointer_register_);
+  // Now that we have unwound the stack we find at the top of the stack the
+  // backtrack that the BeginSubmatch node got.
+  macro->Backtrack();
+  return true;
 }
 
 
-bool EndNode::Emit(RegExpCompiler* compiler) {
+bool EndNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) {
+  if (!variant->is_trivial()) {
+    return variant->Flush(compiler, this);
+  }
   RegExpMacroAssembler* macro = compiler->macro_assembler();
+  if (!label()->is_bound()) {
+    macro->Bind(label());
+  }
   switch (action_) {
     case ACCEPT:
-      if (!label()->is_bound()) Bind(macro);
-      if (info()->at_end) {
-        Label succeed;
-        // LoadCurrentCharacter will go to the label if we are at the end of the
-        // input string.
-        macro->LoadCurrentCharacter(0, &succeed);
-        macro->Backtrack();
-        macro->Bind(&succeed);
-      }
+      EmitInfoChecks(macro, variant);
       macro->Succeed();
       return true;
     case BACKTRACK:
-      if (!label()->is_bound()) Bind(macro);
       ASSERT(!info()->at_end);
-      macro->Backtrack();
+      macro->GoTo(variant->backtrack());
       return true;
+    case NEGATIVE_SUBMATCH_SUCCESS:
+      // This case is handled in a different virtual method.
+      UNREACHABLE();
   }
+  UNIMPLEMENTED();
   return false;
 }
 
@@ -1078,10 +1383,10 @@ void GuardedAlternative::AddGuard(Guard* guard) {
 }
 
 
-ActionNode* ActionNode::StoreRegister(int reg,
-                                      int val,
-                                      RegExpNode* on_success) {
-  ActionNode* result = new ActionNode(STORE_REGISTER, on_success);
+ActionNode* ActionNode::SetRegister(int reg,
+                                    int val,
+                                    RegExpNode* on_success) {
+  ActionNode* result = new ActionNode(SET_REGISTER, on_success);
   result->data_.u_store_register.reg = reg;
   result->data_.u_store_register.value = val;
   return result;
@@ -1102,13 +1407,6 @@ ActionNode* ActionNode::StorePosition(int reg, RegExpNode* on_success) {
 }
 
 
-ActionNode* ActionNode::RestorePosition(int reg, RegExpNode* on_success) {
-  ActionNode* result = new ActionNode(RESTORE_POSITION, on_success);
-  result->data_.u_position_register.reg = reg;
-  return result;
-}
-
-
 ActionNode* ActionNode::BeginSubmatch(int stack_reg,
                                       int position_reg,
                                       RegExpNode* on_success) {
@@ -1119,17 +1417,12 @@ ActionNode* ActionNode::BeginSubmatch(int stack_reg,
 }
 
 
-ActionNode* ActionNode::EscapeSubmatch(int stack_reg,
-                                       bool restore_position,
-                                       int position_reg,
-                                       RegExpNode* on_success) {
-  ActionNode* result = new ActionNode(ESCAPE_SUBMATCH, on_success);
+ActionNode* ActionNode::PositiveSubmatchSuccess(int stack_reg,
+                                                int position_reg,
+                                                RegExpNode* on_success) {
+  ActionNode* result = new ActionNode(POSITIVE_SUBMATCH_SUCCESS, on_success);
   result->data_.u_submatch.stack_pointer_register = stack_reg;
-  if (restore_position) {
-    result->data_.u_submatch.current_position_register = position_reg;
-  } else {
-    result->data_.u_submatch.current_position_register = -1;
-  }
+  result->data_.u_submatch.current_position_register = position_reg;
   return result;
 }
 
@@ -1148,13 +1441,19 @@ FOR_EACH_NODE_TYPE(DEFINE_ACCEPT)
 
 void ChoiceNode::GenerateGuard(RegExpMacroAssembler* macro_assembler,
                                Guard* guard,
-                               Label* on_failure) {
+                               GenerationVariant* variant) {
   switch (guard->op()) {
     case Guard::LT:
-      macro_assembler->IfRegisterGE(guard->reg(), guard->value(), on_failure);
+      ASSERT(!variant->mentions_reg(guard->reg()));
+      macro_assembler->IfRegisterGE(guard->reg(),
+                                    guard->value(),
+                                    variant->backtrack());
       break;
     case Guard::GEQ:
-      macro_assembler->IfRegisterLT(guard->reg(), guard->value(), on_failure);
+      ASSERT(!variant->mentions_reg(guard->reg()));
+      macro_assembler->IfRegisterLT(guard->reg(),
+                                    guard->value(),
+                                    variant->backtrack());
       break;
   }
 }
@@ -1169,13 +1468,22 @@ static inline void EmitAtomNonLetters(
     TextElement elm,
     Vector<const uc16> quarks,
     Label* on_failure,
-    int cp_offset) {
+    int cp_offset,
+    bool check_offset) {
   unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+  // It is vital that this loop is backwards due to the unchecked character
+  // load below.
   for (int i = quarks.length() - 1; i >= 0; i--) {
     uc16 c = quarks[i];
     int length = uncanonicalize.get(c, '\0', chars);
     if (length <= 1) {
-      macro_assembler->LoadCurrentCharacter(cp_offset + i, on_failure);
+      if (check_offset && i == quarks.length() - 1) {
+        macro_assembler->LoadCurrentCharacter(cp_offset + i, on_failure);
+      } else {
+        // Here we don't need to check against the end of the input string
+        // since this character lies before a character that matched.
+        macro_assembler->LoadCurrentCharacterUnchecked(cp_offset + i);
+      }
       macro_assembler->CheckNotCharacter(c, on_failure);
     }
   }
@@ -1216,13 +1524,22 @@ static inline void EmitAtomLetters(
     TextElement elm,
     Vector<const uc16> quarks,
     Label* on_failure,
-    int cp_offset) {
+    int cp_offset,
+    bool check_offset) {
   unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+  // It is vital that this loop is backwards due to the unchecked character
+  // load below.
   for (int i = quarks.length() - 1; i >= 0; i--) {
     uc16 c = quarks[i];
     int length = uncanonicalize.get(c, '\0', chars);
     if (length <= 1) continue;
-    macro_assembler->LoadCurrentCharacter(cp_offset + i, on_failure);
+    if (check_offset && i == quarks.length() - 1) {
+      macro_assembler->LoadCurrentCharacter(cp_offset + i, on_failure);
+    } else {
+      // Here we don't need to check against the end of the input string
+      // since this character lies before a character that matched.
+      macro_assembler->LoadCurrentCharacterUnchecked(cp_offset + i);
+    }
     Label ok;
     ASSERT(unibrow::Ecma262UnCanonicalize::kMaxWidth == 4);
     switch (length) {
@@ -1259,10 +1576,8 @@ static inline void EmitAtomLetters(
 static void EmitCharClass(RegExpMacroAssembler* macro_assembler,
                           RegExpCharacterClass* cc,
                           int cp_offset,
-                          Label* on_failure) {
-  macro_assembler->LoadCurrentCharacter(cp_offset, on_failure);
-  cp_offset++;
-
+                          Label* on_failure,
+                          bool check_offset) {
   ZoneList<CharacterRange>* ranges = cc->ranges();
 
   Label success;
@@ -1279,6 +1594,26 @@ static void EmitCharClass(RegExpMacroAssembler* macro_assembler,
     return;
   }
 
+  if (range_count == 1 &&
+      !cc->is_negated() &&
+      ranges->at(0).IsEverything(0xffff)) {
+    // This is a common case hit by non-anchored expressions.
+    // TODO(erikcorry): We should have a macro assembler instruction that just
+    // checks for end of string without loading the character.
+    if (check_offset) {
+      macro_assembler->LoadCurrentCharacter(cp_offset, on_failure);
+    }
+    return;
+  }
+
+  if (check_offset) {
+    macro_assembler->LoadCurrentCharacter(cp_offset, on_failure);
+  } else {
+    // Here we don't need to check against the end of the input string
+    // since this character lies before a character that matched.
+    macro_assembler->LoadCurrentCharacterUnchecked(cp_offset);
+  }
+
   for (int i = 0; i < range_count - 1; i++) {
     CharacterRange& range = ranges->at(i);
     Label next_range;
@@ -1333,73 +1668,143 @@ static void EmitCharClass(RegExpMacroAssembler* macro_assembler,
 }
 
 
+RegExpNode::LimitResult RegExpNode::LimitVersions(RegExpCompiler* compiler,
+                                                  GenerationVariant* variant) {
+  // TODO(erikcorry): Implement support.
+  if (info_.follows_word_interest ||
+      info_.follows_newline_interest ||
+      info_.follows_start_interest) {
+    return FAIL;
+  }
+
+  // If we are generating a greedy loop then don't stop and don't reuse code.
+  if (variant->stop_node() != NULL) {
+    return CONTINUE;
+  }
+
+  RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
+  if (variant->is_trivial()) {
+    if (label_.is_bound()) {
+      // We are being asked to generate a generic version, but that's already
+      // been done so just go to it.
+      macro_assembler->GoTo(&label_);
+      return DONE;
+    }
+    if (compiler->recursion_depth() >= RegExpCompiler::kMaxRecursion) {
+      // To avoid too deep recursion we push the node to the work queue and just
+      // generate a goto here.
+      compiler->AddWork(this);
+      macro_assembler->GoTo(&label_);
+      return DONE;
+    }
+    // Generate generic version of the node and bind the label for later use.
+    macro_assembler->Bind(&label_);
+    return CONTINUE;
+  }
+
+  // We are being asked to make a non-generic version.  Keep track of how many
+  // non-generic versions we generate so as not to overdo it.
+  variants_generated_++;
+  if (variants_generated_ < kMaxVariantsGenerated &&
+      compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) {
+    return CONTINUE;
+  }
+
+  // If we get here there have been too many variants generated or recursion
+  // is too deep.  Time to switch to a generic version.  The code for
+  // generic versions above can handle deep recursion properly.
+  bool ok = variant->Flush(compiler, this);
+  return ok ? DONE : FAIL;
+}
+
 
-bool TextNode::Emit(RegExpCompiler* compiler) {
+// This generates the code to match a text node.  A text node can contain
+// straight character sequences (possibly to be matched in a case-independent
+// way) and character classes.  In order to be most efficient we test for the
+// simple things first and then move on to the more complicated things.  The
+// simplest thing is a non-letter or a letter if we are matching case.  The
+// next-most simple thing is a case-independent letter.  The least simple is
+// a character class.  Another optimization is that we test the last one first.
+// If that succeeds we don't need to test for the end of the string when we
+// load other characters.
+bool TextNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) {
   RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
-  Bind(macro_assembler);
+  Label *backtrack = variant->backtrack();
+  LimitResult limit_result = LimitVersions(compiler, variant);
+  if (limit_result == FAIL) return false;
+  if (limit_result == DONE) return true;
+  ASSERT(limit_result == CONTINUE);
+
   int element_count = elms_->length();
   ASSERT(element_count != 0);
-  int cp_offset = 0;
   if (info()->at_end) {
-    macro_assembler->Backtrack();
+    macro_assembler->GoTo(backtrack);
     return true;
   }
   // First, handle straight character matches.
-  for (int i = 0; i < element_count; i++) {
+  int checked_up_to = -1;
+  for (int i = element_count - 1; i >= 0; i--) {
     TextElement elm = elms_->at(i);
+    ASSERT(elm.cp_offset >= 0);
+    int cp_offset = variant->cp_offset() + elm.cp_offset;
     if (elm.type == TextElement::ATOM) {
       Vector<const uc16> quarks = elm.data.u_atom->data();
+      int last_cp_offset = cp_offset + quarks.length();
       if (compiler->ignore_case()) {
         EmitAtomNonLetters(macro_assembler,
                            elm,
                            quarks,
-                           on_failure_->label(),
-                           cp_offset);
+                           backtrack,
+                           cp_offset,
+                           checked_up_to < last_cp_offset);
       } else {
         macro_assembler->CheckCharacters(quarks,
                                          cp_offset,
-                                         on_failure_->label());
+                                         backtrack,
+                                         checked_up_to < last_cp_offset);
       }
-      cp_offset += quarks.length();
+      if (last_cp_offset > checked_up_to) checked_up_to = last_cp_offset - 1;
     } else {
       ASSERT_EQ(elm.type, TextElement::CHAR_CLASS);
-      cp_offset++;
     }
   }
   // Second, handle case independent letter matches if any.
   if (compiler->ignore_case()) {
-    cp_offset = 0;
-    for (int i = 0; i < element_count; i++) {
+    for (int i = element_count - 1; i >= 0; i--) {
       TextElement elm = elms_->at(i);
+      int cp_offset = variant->cp_offset() + elm.cp_offset;
       if (elm.type == TextElement::ATOM) {
         Vector<const uc16> quarks = elm.data.u_atom->data();
+        int last_cp_offset = cp_offset + quarks.length();
         EmitAtomLetters(macro_assembler,
                         elm,
                         quarks,
-                        on_failure_->label(),
-                        cp_offset);
-        cp_offset += quarks.length();
-      } else {
-        cp_offset++;
+                        backtrack,
+                        cp_offset,
+                        checked_up_to < last_cp_offset);
+        if (last_cp_offset > checked_up_to) checked_up_to = last_cp_offset - 1;
       }
     }
   }
   // If the fast character matches passed then do the character classes.
-  cp_offset = 0;
-  for (int i = 0; i < element_count; i++) {
+  for (int i = element_count - 1; i >= 0; i--) {
     TextElement elm = elms_->at(i);
+    int cp_offset = variant->cp_offset() + elm.cp_offset;
     if (elm.type == TextElement::CHAR_CLASS) {
       RegExpCharacterClass* cc = elm.data.u_char_class;
-      EmitCharClass(macro_assembler, cc, cp_offset, on_failure_->label());
-      cp_offset++;
-    } else {
-      cp_offset += elm.data.u_atom->data().length();
+      EmitCharClass(macro_assembler,
+                    cc,
+                    cp_offset,
+                    backtrack,
+                    checked_up_to < cp_offset);
+      if (cp_offset > checked_up_to) checked_up_to = cp_offset;
     }
   }
 
-  compiler->AddWork(on_failure_);
-  macro_assembler->AdvanceCurrentPosition(cp_offset);
-  return on_success()->GoTo(compiler);
+  GenerationVariant new_variant(*variant);
+  new_variant.set_cp_offset(checked_up_to + 1);
+  RecursionCheck rc(compiler);
+  return on_success()->Emit(compiler, &new_variant);
 }
 
 
@@ -1419,141 +1824,257 @@ void TextNode::MakeCaseIndependent() {
 }
 
 
-bool ChoiceNode::Emit(RegExpCompiler* compiler) {
-  int choice_count = alternatives_->length();
+int TextNode::GreedyLoopTextLength() {
+  TextElement elm = elms_->at(elms_->length() - 1);
+  if (elm.type == TextElement::CHAR_CLASS) {
+    return elm.cp_offset + 1;
+  } else {
+    return elm.cp_offset + elm.data.u_atom->data().length();
+  }
+}
+
+
+// Finds the fixed match length of a sequence of nodes that goes from
+// this alternative and back to this choice node.  If there are variable
+// length nodes or other complications in the way then return a sentinel
+// value indicating that a greedy loop cannot be constructed.
+int ChoiceNode::GreedyLoopTextLength(GuardedAlternative* alternative) {
+  int length = 0;
+  RegExpNode* node = alternative->node();
+  // Later we will generate code for all these text nodes using recursion
+  // so we have to limit the max number.
+  int recursion_depth = 0;
+  while (node != this) {
+    if (recursion_depth++ > RegExpCompiler::kMaxRecursion) {
+      return kNodeIsTooComplexForGreedyLoops;
+    }
+    NodeInfo* info = node->info();
+    if (info->follows_word_interest ||
+        info->follows_newline_interest ||
+        info->follows_start_interest) {
+      return kNodeIsTooComplexForGreedyLoops;
+    }
+    int node_length = node->GreedyLoopTextLength();
+    if (node_length == kNodeIsTooComplexForGreedyLoops) {
+      return kNodeIsTooComplexForGreedyLoops;
+    }
+    length += node_length;
+    SeqRegExpNode* seq_node = static_cast<SeqRegExpNode*>(node);
+    node = seq_node->on_success();
+  }
+  return length;
+}
+
+
+bool LoopChoiceNode::Emit(RegExpCompiler* compiler,
+                          GenerationVariant* variant) {
+  RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
+  if (variant->stop_node() == this) {
+    int text_length = GreedyLoopTextLength(&(alternatives_->at(0)));
+    ASSERT(text_length != kNodeIsTooComplexForGreedyLoops);
+    // Update the counter-based backtracking info on the stack.  This is an
+    // optimization for greedy loops (see below).
+    ASSERT(variant->cp_offset() == text_length);
+    macro_assembler->AdvanceCurrentPosition(text_length);
+    macro_assembler->GoTo(variant->loop_label());
+    return true;
+  }
+  ASSERT(variant->stop_node() == NULL);
+  if (!variant->is_trivial()) {
+    return variant->Flush(compiler, this);
+  }
+  return ChoiceNode::Emit(compiler, variant);
+}
+
+
+bool ChoiceNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) {
   RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
-  Bind(macro_assembler);
+  int choice_count = alternatives_->length();
+#ifdef DEBUG
+  for (int i = 0; i < choice_count - 1; i++) {
+    GuardedAlternative alternative = alternatives_->at(i);
+    ZoneList<Guard*>* guards = alternative.guards();
+    int guard_count = (guards == NULL) ? 0 : guards->length();
+    for (int j = 0; j < guard_count; j++) {
+      ASSERT(!variant->mentions_reg(guards->at(j)->reg()));
+    }
+  }
+#endif
+
+  LimitResult limit_result = LimitVersions(compiler, variant);
+  if (limit_result == DONE) return true;
+  if (limit_result == FAIL) return false;
+  ASSERT(limit_result == CONTINUE);
+
+  RecursionCheck rc(compiler);
+
+  GenerationVariant* current_variant = variant;
+
+  int text_length = GreedyLoopTextLength(&(alternatives_->at(0)));
+  bool greedy_loop = false;
+  Label greedy_loop_label;
+  GenerationVariant counter_backtrack_variant(&greedy_loop_label);
+  if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) {
+    // Here we have special handling for greedy loops containing only text nodes
+    // and other simple nodes.  These are handled by pushing the current
+    // position on the stack and then incrementing the current position each
+    // time around the switch.  On backtrack we decrement the current position
+    // and check it against the pushed value.  This avoids pushing backtrack
+    // information for each iteration of the loop, which could take up a lot of
+    // space.
+    greedy_loop = true;
+    ASSERT(variant->stop_node() == NULL);
+    macro_assembler->PushCurrentPosition();
+    current_variant = &counter_backtrack_variant;
+    Label greedy_match_failed;
+    GenerationVariant greedy_match_variant(&greedy_match_failed);
+    Label loop_label;
+    macro_assembler->Bind(&loop_label);
+    greedy_match_variant.set_stop_node(this);
+    greedy_match_variant.set_loop_label(&loop_label);
+    bool ok = alternatives_->at(0).node()->Emit(compiler,
+                                                &greedy_match_variant);
+    macro_assembler->Bind(&greedy_match_failed);
+    if (!ok) {
+      greedy_loop_label.Unuse();
+      return false;
+    }
+  }
+
+  Label second_choice;  // For use in greedy matches.
+  macro_assembler->Bind(&second_choice);
+
   // For now we just call all choices one after the other.  The idea ultimately
   // is to use the Dispatch table to try only the relevant ones.
-  for (int i = 0; i < choice_count - 1; i++) {
+  for (int i = greedy_loop ? 1 : 0; i < choice_count - 1; i++) {
     GuardedAlternative alternative = alternatives_->at(i);
     Label after;
-    Label after_no_pop_cp;
     ZoneList<Guard*>* guards = alternative.guards();
-    if (guards != NULL) {
-      int guard_count = guards->length();
-      for (int j = 0; j < guard_count; j++) {
-        GenerateGuard(macro_assembler, guards->at(j), &after_no_pop_cp);
-      }
+    int guard_count = (guards == NULL) ? 0 : guards->length();
+    GenerationVariant new_variant(*current_variant);
+    new_variant.set_backtrack(&after);
+    for (int j = 0; j < guard_count; j++) {
+      GenerateGuard(macro_assembler, guards->at(j), &new_variant);
     }
-    macro_assembler->PushCurrentPosition();
-    macro_assembler->PushBacktrack(&after);
-    if (!alternative.node()->GoTo(compiler)) {
+    if (!alternative.node()->Emit(compiler, &new_variant)) {
       after.Unuse();
-      after_no_pop_cp.Unuse();
       return false;
     }
     macro_assembler->Bind(&after);
-    macro_assembler->PopCurrentPosition();
-    macro_assembler->Bind(&after_no_pop_cp);
   }
   GuardedAlternative alternative = alternatives_->at(choice_count - 1);
   ZoneList<Guard*>* guards = alternative.guards();
-  if (guards != NULL) {
-    int guard_count = guards->length();
-    for (int j = 0; j < guard_count; j++) {
-      GenerateGuard(macro_assembler, guards->at(j), on_failure_->label());
-    }
-  }
-  if (!on_failure_->IsBacktrack()) {
-    ASSERT_NOT_NULL(on_failure_ -> label());
-    macro_assembler->PushBacktrack(on_failure_->label());
-    compiler->AddWork(on_failure_);
-  }
-  if (!alternative.node()->GoTo(compiler)) {
-    return false;
+  int guard_count = (guards == NULL) ? 0 : guards->length();
+  for (int j = 0; j < guard_count; j++) {
+    GenerateGuard(macro_assembler, guards->at(j), current_variant);
+  }
+  bool ok = alternative.node()->Emit(compiler, current_variant);
+  if (!ok) return false;
+  if (greedy_loop) {
+    macro_assembler->Bind(&greedy_loop_label);
+    // If we have unwound to the bottom then backtrack.
+    macro_assembler->CheckGreedyLoop(variant->backtrack());
+    // Otherwise try the second priority at an earlier position.
+    macro_assembler->AdvanceCurrentPosition(-text_length);
+    macro_assembler->GoTo(&second_choice);
   }
   return true;
 }
 
 
-bool ActionNode::Emit(RegExpCompiler* compiler) {
+bool ActionNode::Emit(RegExpCompiler* compiler, GenerationVariant* variant) {
   RegExpMacroAssembler* macro = compiler->macro_assembler();
-  Bind(macro);
+  LimitResult limit_result = LimitVersions(compiler, variant);
+  if (limit_result == DONE) return true;
+  if (limit_result == FAIL) return false;
+  ASSERT(limit_result == CONTINUE);
+
+  RecursionCheck rc(compiler);
+
   switch (type_) {
-    case STORE_REGISTER:
-      macro->SetRegister(data_.u_store_register.reg,
-                         data_.u_store_register.value);
-      break;
+    case STORE_POSITION: {
+      GenerationVariant::DeferredCapture
+          new_capture(data_.u_position_register.reg, variant);
+      GenerationVariant new_variant = *variant;
+      new_variant.add_action(&new_capture);
+      return on_success()->Emit(compiler, &new_variant);
+    }
     case INCREMENT_REGISTER: {
-      Label undo;
-      macro->PushBacktrack(&undo);
-      macro->AdvanceRegister(data_.u_increment_register.reg, 1);
-      bool ok = on_success()->GoTo(compiler);
-      if (!ok) {
-        undo.Unuse();
-        return false;
-      }
-      macro->Bind(&undo);
-      macro->AdvanceRegister(data_.u_increment_register.reg, -1);
-      macro->Backtrack();
-      break;
+      GenerationVariant::DeferredIncrementRegister
+          new_increment(data_.u_increment_register.reg);
+      GenerationVariant new_variant = *variant;
+      new_variant.add_action(&new_increment);
+      return on_success()->Emit(compiler, &new_variant);
     }
-    case STORE_POSITION: {
-      Label undo;
-      macro->PushRegister(data_.u_position_register.reg);
-      macro->PushBacktrack(&undo);
-      macro->WriteCurrentPositionToRegister(data_.u_position_register.reg);
-      bool ok = on_success()->GoTo(compiler);
-      if (!ok) {
-        undo.Unuse();
-        return false;
-      }
-      macro->Bind(&undo);
-      macro->PopRegister(data_.u_position_register.reg);
-      macro->Backtrack();
-      break;
+    case SET_REGISTER: {
+      GenerationVariant::DeferredSetRegister
+          new_set(data_.u_store_register.reg, data_.u_store_register.value);
+      GenerationVariant new_variant = *variant;
+      new_variant.add_action(&new_set);
+      return on_success()->Emit(compiler, &new_variant);
     }
-    case RESTORE_POSITION:
-      macro->ReadCurrentPositionFromRegister(
-          data_.u_position_register.reg);
-      break;
     case BEGIN_SUBMATCH:
+      if (!variant->is_trivial()) return variant->Flush(compiler, this);
       macro->WriteCurrentPositionToRegister(
-          data_.u_submatch.current_position_register);
+          data_.u_submatch.current_position_register, 0);
       macro->WriteStackPointerToRegister(
           data_.u_submatch.stack_pointer_register);
-      break;
-    case ESCAPE_SUBMATCH:
+      return on_success()->Emit(compiler, variant);
+    case POSITIVE_SUBMATCH_SUCCESS:
+      if (!variant->is_trivial()) return variant->Flush(compiler, this);
+      // TODO(erikcorry): Implement support.
+      if (info()->follows_word_interest ||
+          info()->follows_newline_interest ||
+          info()->follows_start_interest) {
+        return false;
+      }
       if (info()->at_end) {
         Label at_end;
         // Load current character jumps to the label if we are beyond the string
         // end.
         macro->LoadCurrentCharacter(0, &at_end);
-        macro->Backtrack();
+        macro->GoTo(variant->backtrack());
         macro->Bind(&at_end);
       }
-      if (data_.u_submatch.current_position_register != -1) {
-        macro->ReadCurrentPositionFromRegister(
-            data_.u_submatch.current_position_register);
-      }
+      macro->ReadCurrentPositionFromRegister(
+          data_.u_submatch.current_position_register);
       macro->ReadStackPointerFromRegister(
           data_.u_submatch.stack_pointer_register);
-      break;
+      return on_success()->Emit(compiler, variant);
     default:
       UNREACHABLE();
       return false;
   }
-  return on_success()->GoTo(compiler);
 }
 
 
-bool BackReferenceNode::Emit(RegExpCompiler* compiler) {
+bool BackReferenceNode::Emit(RegExpCompiler* compiler,
+                             GenerationVariant* variant) {
   RegExpMacroAssembler* macro = compiler->macro_assembler();
-  Bind(macro);
+  if (!variant->is_trivial()) {
+    return variant->Flush(compiler, this);
+  }
+
+  LimitResult limit_result = LimitVersions(compiler, variant);
+  if (limit_result == DONE) return true;
+  if (limit_result == FAIL) return false;
+  ASSERT(limit_result == CONTINUE);
+
+  RecursionCheck rc(compiler);
+
   ASSERT_EQ(start_reg_ + 1, end_reg_);
   if (info()->at_end) {
     // If we are constrained to match at the end of the input then succeed
     // iff the back reference is empty.
-    macro->CheckNotRegistersEqual(start_reg_, end_reg_, on_failure_->label());
+    macro->CheckNotRegistersEqual(start_reg_, end_reg_, variant->backtrack());
   } else {
     if (compiler->ignore_case()) {
-      macro->CheckNotBackReferenceIgnoreCase(start_reg_, on_failure_->label());
+      macro->CheckNotBackReferenceIgnoreCase(start_reg_, variant->backtrack());
     } else {
-      macro->CheckNotBackReference(start_reg_, on_failure_->label());
+      macro->CheckNotBackReference(start_reg_, variant->backtrack());
     }
   }
-  return on_success()->GoTo(compiler);
+  return on_success()->Emit(compiler, variant);
 }
 
 
@@ -1571,9 +2092,9 @@ class DotPrinter: public NodeVisitor {
         stream_(&alloc_) { }
   void PrintNode(const char* label, RegExpNode* node);
   void Visit(RegExpNode* node);
-  void PrintOnFailure(RegExpNode* from, RegExpNode* on_failure);
   void PrintAttributes(RegExpNode* from);
   StringStream* stream() { return &stream_; }
+  void PrintOnFailure(RegExpNode* from, RegExpNode* to);
 #define DECLARE_VISIT(Type)                                          \
   virtual void Visit##Type(Type##Node* that);
 FOR_EACH_NODE_TYPE(DECLARE_VISIT)
@@ -1615,7 +2136,6 @@ void DotPrinter::Visit(RegExpNode* node) {
 
 
 void DotPrinter::PrintOnFailure(RegExpNode* from, RegExpNode* on_failure) {
-  if (on_failure->IsBacktrack()) return;
   stream()->Add("  n%p -> n%p [style=dotted];\n", from, on_failure);
   Visit(on_failure);
 }
@@ -1740,7 +2260,6 @@ void DotPrinter::VisitChoice(ChoiceNode* that) {
     PrintAttributes(that);
     TableEntryBodyPrinter body_printer(stream(), that);
     that->GetTable(ignore_case_)->ForEach(&body_printer);
-    PrintOnFailure(that, that->on_failure());
   } else {
     stream()->Add("  n%p [shape=Mrecord, label=\"?\"];\n", that);
     for (int i = 0; i < that->alternatives()->length(); i++) {
@@ -1785,7 +2304,6 @@ void DotPrinter::VisitText(TextNode* that) {
   PrintAttributes(that);
   stream()->Add("  n%p -> n%p;\n", that, that->on_success());
   Visit(that->on_success());
-  PrintOnFailure(that, that->on_failure());
 }
 
 
@@ -1797,7 +2315,6 @@ void DotPrinter::VisitBackReference(BackReferenceNode* that) {
   PrintAttributes(that);
   stream()->Add("  n%p -> n%p;\n", that, that->on_success());
   Visit(that->on_success());
-  PrintOnFailure(that, that->on_failure());
 }
 
 
@@ -1810,7 +2327,7 @@ void DotPrinter::VisitEnd(EndNode* that) {
 void DotPrinter::VisitAction(ActionNode* that) {
   stream()->Add("  n%p [", that);
   switch (that->type_) {
-    case ActionNode::STORE_REGISTER:
+    case ActionNode::SET_REGISTER:
       stream()->Add("label=\"$%i:=%i\", shape=octagon",
                     that->data_.u_store_register.reg,
                     that->data_.u_store_register.value);
@@ -1823,22 +2340,19 @@ void DotPrinter::VisitAction(ActionNode* that) {
       stream()->Add("label=\"$%i:=$pos\", shape=octagon",
                     that->data_.u_position_register.reg);
       break;
-    case ActionNode::RESTORE_POSITION:
-      stream()->Add("label=\"$pos:=$%i\", shape=octagon",
-                    that->data_.u_position_register.reg);
-      break;
     case ActionNode::BEGIN_SUBMATCH:
       stream()->Add("label=\"$%i:=$pos,begin\", shape=septagon",
                     that->data_.u_submatch.current_position_register);
       break;
-    case ActionNode::ESCAPE_SUBMATCH:
+    case ActionNode::POSITIVE_SUBMATCH_SUCCESS:
       stream()->Add("label=\"escape\", shape=septagon");
       break;
   }
   stream()->Add("];\n");
   PrintAttributes(that);
-  stream()->Add("  n%p -> n%p;\n", that, that->on_success());
-  Visit(that->on_success());
+  RegExpNode* successor = that->on_success();
+  stream()->Add("  n%p -> n%p;\n", that, successor);
+  Visit(successor);
 }
 
 
@@ -1895,40 +2409,35 @@ void RegExpEngine::DotPrint(const char* label,
 
 
 RegExpNode* RegExpAtom::ToNode(RegExpCompiler* compiler,
-                               RegExpNode* on_success,
-                               RegExpNode* on_failure) {
+                               RegExpNode* on_success) {
   ZoneList<TextElement>* elms = new ZoneList<TextElement>(1);
   elms->Add(TextElement::Atom(this));
-  return new TextNode(elms, on_success, on_failure);
+  return new TextNode(elms, on_success);
 }
 
 
 RegExpNode* RegExpText::ToNode(RegExpCompiler* compiler,
-                               RegExpNode* on_success,
-                               RegExpNode* on_failure) {
-  return new TextNode(elements(), on_success, on_failure);
+                               RegExpNode* on_success) {
+  return new TextNode(elements(), on_success);
 }
 
 
 RegExpNode* RegExpCharacterClass::ToNode(RegExpCompiler* compiler,
-                                         RegExpNode* on_success,
-                                         RegExpNode* on_failure) {
+                                         RegExpNode* on_success) {
   ZoneList<TextElement>* elms = new ZoneList<TextElement>(1);
   elms->Add(TextElement::CharClass(this));
-  return new TextNode(elms, on_success, on_failure);
+  return new TextNode(elms, on_success);
 }
 
 
 RegExpNode* RegExpDisjunction::ToNode(RegExpCompiler* compiler,
-                                      RegExpNode* on_success,
-                                      RegExpNode* on_failure) {
+                                      RegExpNode* on_success) {
   ZoneList<RegExpTree*>* alternatives = this->alternatives();
   int length = alternatives->length();
-  ChoiceNode* result = new ChoiceNode(length, on_failure);
+  ChoiceNode* result = new ChoiceNode(length);
   for (int i = 0; i < length; i++) {
     GuardedAlternative alternative(alternatives->at(i)->ToNode(compiler,
-                                                               on_success,
-                                                               on_failure));
+                                                               on_success));
     result->AddAlternative(alternative);
   }
   return result;
@@ -1936,15 +2445,13 @@ RegExpNode* RegExpDisjunction::ToNode(RegExpCompiler* compiler,
 
 
 RegExpNode* RegExpQuantifier::ToNode(RegExpCompiler* compiler,
-                                     RegExpNode* on_success,
-                                     RegExpNode* on_failure) {
+                                     RegExpNode* on_success) {
   return ToNode(min(),
                 max(),
                 is_greedy(),
                 body(),
                 compiler,
-                on_success,
-                on_failure);
+                on_success);
 }
 
 
@@ -1953,8 +2460,7 @@ RegExpNode* RegExpQuantifier::ToNode(int min,
                                      bool is_greedy,
                                      RegExpTree* body,
                                      RegExpCompiler* compiler,
-                                     RegExpNode* on_success,
-                                     RegExpNode* on_failure) {
+                                     RegExpNode* on_success) {
   // x{f, t} becomes this:
   //
   //             (r++)<-.
@@ -1972,11 +2478,11 @@ RegExpNode* RegExpQuantifier::ToNode(int min,
   bool has_max = max < RegExpQuantifier::kInfinity;
   bool needs_counter = has_min || has_max;
   int reg_ctr = needs_counter ? compiler->AllocateRegister() : -1;
-  ChoiceNode* center = new ChoiceNode(2, on_failure);
+  ChoiceNode* center = new LoopChoiceNode(2);
   RegExpNode* loop_return = needs_counter
       ? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center))
       : static_cast<RegExpNode*>(center);
-  RegExpNode* body_node = body->ToNode(compiler, loop_return, on_failure);
+  RegExpNode* body_node = body->ToNode(compiler, loop_return);
   GuardedAlternative body_alt(body_node);
   if (has_max) {
     Guard* body_guard = new Guard(reg_ctr, Guard::LT, max);
@@ -1995,7 +2501,7 @@ RegExpNode* RegExpQuantifier::ToNode(int min,
     center->AddAlternative(body_alt);
   }
   if (needs_counter) {
-    return ActionNode::StoreRegister(reg_ctr, 0, center);
+    return ActionNode::SetRegister(reg_ctr, 0, center);
   } else {
     return center;
   }
@@ -2003,8 +2509,7 @@ RegExpNode* RegExpQuantifier::ToNode(int min,
 
 
 RegExpNode* RegExpAssertion::ToNode(RegExpCompiler* compiler,
-                                    RegExpNode* on_success,
-                                    RegExpNode* on_failure) {
+                                    RegExpNode* on_success) {
   NodeInfo info;
   switch (type()) {
     case START_OF_LINE:
@@ -2028,108 +2533,85 @@ RegExpNode* RegExpAssertion::ToNode(RegExpCompiler* compiler,
 
 
 RegExpNode* RegExpBackReference::ToNode(RegExpCompiler* compiler,
-                                        RegExpNode* on_success,
-                                        RegExpNode* on_failure) {
+                                        RegExpNode* on_success) {
   return new BackReferenceNode(RegExpCapture::StartRegister(index()),
                                RegExpCapture::EndRegister(index()),
-                               on_success,
-                               on_failure);
+                               on_success);
 }
 
 
 RegExpNode* RegExpEmpty::ToNode(RegExpCompiler* compiler,
-                                RegExpNode* on_success,
-                                RegExpNode* on_failure) {
+                                RegExpNode* on_success) {
   return on_success;
 }
 
 
 RegExpNode* RegExpLookahead::ToNode(RegExpCompiler* compiler,
-                                    RegExpNode* on_success,
-                                    RegExpNode* on_failure) {
+                                    RegExpNode* on_success) {
   int stack_pointer_register = compiler->AllocateRegister();
   int position_register = compiler->AllocateRegister();
+  RegExpNode* success;
   if (is_positive()) {
-    // begin submatch scope
-    // $reg = $pos
-    // if [body]
-    // then
-    //   $pos = $reg
-    //   escape submatch scope (drop all backtracks created in scope)
-    //   succeed
-    // else
-    //   end submatch scope (nothing to clean up, just exit the scope)
-    //   fail
     return ActionNode::BeginSubmatch(
         stack_pointer_register,
         position_register,
         body()->ToNode(
             compiler,
-            ActionNode::EscapeSubmatch(
-                stack_pointer_register,
-                true,                    // Also restore input position.
-                position_register,
-                on_success),
-            on_failure));
+            ActionNode::PositiveSubmatchSuccess(stack_pointer_register,
+                                                position_register,
+                                                on_success)));
   } else {
-    // begin submatch scope
-    // try
-    // first if (body)
-    //       then
-    //         escape submatch scope
-    //         fail
-    //       else
-    //         backtrack
-    // second
-    //       end submatch scope
-    //       restore current position
-    //       succeed
-    ChoiceNode* try_node =
-        new ChoiceNode(1, ActionNode::RestorePosition(position_register,
-                                                      on_success));
-    RegExpNode* body_node = body()->ToNode(
-        compiler,
-        ActionNode::EscapeSubmatch(stack_pointer_register,
-                                   false,        // Don't also restore position
-                                   0,            // Unused arguments.
-                                   on_failure),
-        compiler->backtrack());
-    GuardedAlternative body_alt(body_node);
-    try_node->AddAlternative(body_alt);
+    // We use a ChoiceNode for a negative lookahead because it has most of
+    // the characteristics we need.  It has the body of the lookahead as its
+    // first alternative and the expression after the lookahead of the second
+    // alternative.  If the first alternative succeeds then the
+    // NegativeSubmatchSuccess will unwind the stack including everything the
+    // choice node set up and backtrack.  If the first alternative fails then
+    // the second alternative is tried, which is exactly the desired result
+    // for a negative lookahead.  In the case where the dispatch table
+    // determines that the first alternative cannot match we will save time
+    // by not trying it.  Things are not quite so well-optimized if the
+    // dispatch table determines that the second alternative cannot match.
+    // In this case we could optimize by immediately backtracking.
+    ChoiceNode* choice_node = new ChoiceNode(2);
+    GuardedAlternative body_alt(
+        body()->ToNode(
+            compiler,
+            success = new NegativeSubmatchSuccess(stack_pointer_register,
+                                                  position_register)));
+    choice_node->AddAlternative(body_alt);
+    choice_node->AddAlternative(GuardedAlternative(on_success));
     return ActionNode::BeginSubmatch(stack_pointer_register,
                                      position_register,
-                                     try_node);
+                                     choice_node);
   }
 }
 
 
 RegExpNode* RegExpCapture::ToNode(RegExpCompiler* compiler,
-                                  RegExpNode* on_success,
-                                  RegExpNode* on_failure) {
-  return ToNode(body(), index(), compiler, on_success, on_failure);
+                                  RegExpNode* on_success) {
+  return ToNode(body(), index(), compiler, on_success);
 }
 
 
 RegExpNode* RegExpCapture::ToNode(RegExpTree* body,
                                   int index,
                                   RegExpCompiler* compiler,
-                                  RegExpNode* on_success,
-                                  RegExpNode* on_failure) {
+                                  RegExpNode* on_success) {
   int start_reg = RegExpCapture::StartRegister(index);
   int end_reg = RegExpCapture::EndRegister(index);
   RegExpNode* store_end = ActionNode::StorePosition(end_reg, on_success);
-  RegExpNode* body_node = body->ToNode(compiler, store_end, on_failure);
+  RegExpNode* body_node = body->ToNode(compiler, store_end);
   return ActionNode::StorePosition(start_reg, body_node);
 }
 
 
 RegExpNode* RegExpAlternative::ToNode(RegExpCompiler* compiler,
-                                      RegExpNode* on_success,
-                                      RegExpNode* on_failure) {
+                                      RegExpNode* on_success) {
   ZoneList<RegExpTree*>* children = nodes();
   RegExpNode* current = on_success;
   for (int i = children->length() - 1; i >= 0; i--) {
-    current = children->at(i)->ToNode(compiler, current, on_failure);
+    current = children->at(i)->ToNode(compiler, current);
   }
   return current;
 }
@@ -2400,9 +2882,7 @@ RegExpNode* ActionNode::PropagateForward(NodeInfo* info) {
   full_info.AddFromPreceding(info);
   bool cloned = false;
   ActionNode* action = EnsureSibling(this, &full_info, &cloned);
-  if (cloned && type_ != ESCAPE_SUBMATCH) {
-    action->set_on_success(action->on_success()->PropagateForward(info));
-  }
+  action->set_on_success(action->on_success()->PropagateForward(info));
   return action;
 }
 
@@ -2421,9 +2901,6 @@ RegExpNode* ChoiceNode::PropagateForward(NodeInfo* info) {
       alternative.set_node(alternative.node()->PropagateForward(info));
       choice->alternatives()->Add(alternative);
     }
-    if (!choice->on_failure_->IsBacktrack()) {
-      choice->on_failure_ = choice->on_failure_->PropagateForward(info);
-    }
   }
   return choice;
 }
@@ -2624,12 +3101,29 @@ void Analysis::VisitEnd(EndNode* that) {
 }
 
 
+void TextNode::CalculateOffsets() {
+  int element_count = elements()->length();
+  // Set up the offsets of the elements relative to the start.  This is a fixed
+  // quantity since a TextNode can only contain fixed-width things.
+  int cp_offset = 0;
+  for (int i = 0; i < element_count; i++) {
+    TextElement& elm = elements()->at(i);
+    elm.cp_offset = cp_offset;
+    if (elm.type == TextElement::ATOM) {
+      cp_offset += elm.data.u_atom->data().length();
+    } else {
+      cp_offset++;
+      Vector<const uc16> quarks = elm.data.u_atom->data();
+    }
+  }
+}
+
+
 void Analysis::VisitText(TextNode* that) {
   if (ignore_case_) {
     that->MakeCaseIndependent();
   }
   EnsureAnalyzed(that->on_success());
-  EnsureAnalyzed(that->on_failure());
   NodeInfo* info = that->info();
   NodeInfo* next_info = that->on_success()->info();
   // If the following node is interested in what it follows then this
@@ -2637,14 +3131,16 @@ void Analysis::VisitText(TextNode* that) {
   info->determine_newline = next_info->follows_newline_interest;
   info->determine_word = next_info->follows_word_interest;
   info->determine_start = next_info->follows_start_interest;
+  that->CalculateOffsets();
 }
 
 
 void Analysis::VisitAction(ActionNode* that) {
-  EnsureAnalyzed(that->on_success());
+  RegExpNode* target = that->on_success();
+  EnsureAnalyzed(target);
   // If the next node is interested in what it follows then this node
   // has to be interested too so it can pass the information on.
-  that->info()->AddFromFollowing(that->on_success()->info());
+  that->info()->AddFromFollowing(target->info());
 }
 
 
@@ -2657,13 +3153,11 @@ void Analysis::VisitChoice(ChoiceNode* that) {
     // this node also, so it can pass it on.
     info->AddFromFollowing(node->info());
   }
-  EnsureAnalyzed(that->on_failure());
 }
 
 
 void Analysis::VisitBackReference(BackReferenceNode* that) {
   EnsureAnalyzed(that->on_success());
-  EnsureAnalyzed(that->on_failure());
 }
 
 
@@ -2746,7 +3240,7 @@ RegExpNode* TextNode::ExpandLocal(NodeInfo* info) {
       } else {
         // If this character class contains both word and non-word
         // characters we need to split it into two.
-        ChoiceNode* result = new ChoiceNode(2, on_failure());
+        ChoiceNode* result = new ChoiceNode(2);
         // Welcome to the family, son!
         result->set_siblings(this->siblings());
         *result->info() = *this->info();
@@ -2754,16 +3248,14 @@ RegExpNode* TextNode::ExpandLocal(NodeInfo* info) {
         result->info()->AddAssumptions(info);
         RegExpNode* word_node
             = new TextNode(new RegExpCharacterClass(word, false),
-                           on_success(),
-                           on_failure());
+                           on_success());
         word_node->info()->determine_word = true;
         word_node->info()->does_determine_word = true;
         word_node->info()->is_word = NodeInfo::TRUE;
         result->alternatives()->Add(GuardedAlternative(word_node));
         RegExpNode* non_word_node
             = new TextNode(new RegExpCharacterClass(non_word, false),
-                           on_success(),
-                           on_failure());
+                           on_success());
         non_word_node->info()->determine_word = true;
         non_word_node->info()->does_determine_word = true;
         non_word_node->info()->is_word = NodeInfo::FALSE;
@@ -2974,21 +3466,22 @@ void DispatchTableConstructor::VisitText(TextNode* that) {
 
 
 void DispatchTableConstructor::VisitAction(ActionNode* that) {
-  that->on_success()->Accept(this);
+  RegExpNode* target = that->on_success();
+  target->Accept(this);
 }
 
 
 Handle<FixedArray> RegExpEngine::Compile(RegExpParseResult* input,
                                          RegExpNode** node_return,
                                          bool ignore_case,
-                                         bool is_multiline) {
+                                         bool is_multiline,
+                                         Handle<String> pattern) {
   RegExpCompiler compiler(input->capture_count, ignore_case);
   // Wrap the body of the regexp in capture #0.
   RegExpNode* captured_body = RegExpCapture::ToNode(input->tree,
                                                     0,
                                                     &compiler,
-                                                    compiler.accept(),
-                                                    compiler.backtrack());
+                                                    compiler.accept());
   // Add a .*? at the beginning, outside the body capture.
   // Note: We could choose to not add this if the regexp is anchored at
   //   the start of the input but I'm not sure how best to do that and
@@ -2999,8 +3492,7 @@ Handle<FixedArray> RegExpEngine::Compile(RegExpParseResult* input,
                                               false,
                                               new RegExpCharacterClass('*'),
                                               &compiler,
-                                              captured_body,
-                                              compiler.backtrack());
+                                              captured_body);
   if (node_return != NULL) *node_return = node;
   Analysis analysis(ignore_case);
   analysis.EnsureAnalyzed(node);
@@ -3024,14 +3516,16 @@ Handle<FixedArray> RegExpEngine::Compile(RegExpParseResult* input,
                                              (input->capture_count + 1) * 2);
     return compiler.Assemble(&macro_assembler,
                              node,
-                             input->capture_count);
+                             input->capture_count,
+                             pattern);
 #endif
   }
   EmbeddedVector<byte, 1024> codes;
   RegExpMacroAssemblerIrregexp macro_assembler(codes);
   return compiler.Assemble(&macro_assembler,
                            node,
-                           input->capture_count);
+                           input->capture_count,
+                           pattern);
 }
 
 
index 3ab6651..53c8170 100644 (file)
@@ -202,6 +202,7 @@ class CharacterRange {
   uc16 to() const { return to_; }
   void set_to(uc16 value) { to_ = value; }
   bool is_valid() { return from_ <= to_; }
+  bool IsEverything(uc16 max) { return from_ == 0 && to_ >= max; }
   bool IsSingleton() { return (from_ == to_); }
   void AddCaseEquivalents(ZoneList<CharacterRange>* ranges);
   static void Split(ZoneList<CharacterRange>* base,
@@ -346,6 +347,7 @@ class OutSet: public ZoneObject {
   uint32_t first_;
   ZoneList<unsigned>* remaining_;
   ZoneList<OutSet*>* successors_;
+  friend class GenerationVariant;
 };
 
 
@@ -432,7 +434,7 @@ class TextElement {
  public:
   enum Type {UNINITIALIZED, ATOM, CHAR_CLASS};
   TextElement() : type(UNINITIALIZED) { }
-  explicit TextElement(Type t) : type(t) { }
+  explicit TextElement(Type t) : type(t), cp_offset(-1) { }
   static TextElement Atom(RegExpAtom* atom);
   static TextElement CharClass(RegExpCharacterClass* char_class);
   Type type;
@@ -440,9 +442,13 @@ class TextElement {
     RegExpAtom* u_atom;
     RegExpCharacterClass* u_char_class;
   } data;
+  int cp_offset;
 };
 
 
+class GenerationVariant;
+
+
 struct NodeInfo {
   enum TriBool {
     UNKNOWN = -1, FALSE = 0, TRUE = 1
@@ -607,17 +613,17 @@ class SiblingList {
 
 class RegExpNode: public ZoneObject {
  public:
+  RegExpNode() : variants_generated_(0) { }
   virtual ~RegExpNode() { }
   virtual void Accept(NodeVisitor* visitor) = 0;
   // Generates a goto to this node or actually generates the code at this point.
   // Until the implementation is complete we will return true for success and
   // false for failure.
-  virtual bool GoTo(RegExpCompiler* compiler);
-  Label* label();
-
-  // Until the implementation is complete we will return true for success and
-  // false for failure.
-  virtual bool Emit(RegExpCompiler* compiler) = 0;
+  virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant) = 0;
+  static const int kNodeIsTooComplexForGreedyLoops = -1;
+  virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; }
+  Label* label() { return &label_; }
+  static const int kMaxVariantsGenerated = 10;
 
   RegExpNode* EnsureExpanded(NodeInfo* info);
   virtual RegExpNode* ExpandLocal(NodeInfo* info) = 0;
@@ -630,7 +636,6 @@ class RegExpNode: public ZoneObject {
   virtual RegExpNode* PropagateForward(NodeInfo* info) = 0;
 
   NodeInfo* info() { return &info_; }
-  virtual bool IsBacktrack() { return false; }
 
   void AddSibling(RegExpNode* node) { siblings_.Add(node); }
 
@@ -645,6 +650,9 @@ class RegExpNode: public ZoneObject {
   void set_siblings(SiblingList* other) { siblings_ = *other; }
 
  protected:
+  enum LimitResult { DONE, FAIL, CONTINUE };
+  LimitResult LimitVersions(RegExpCompiler* compiler,
+                            GenerationVariant* variant);
 
   // Returns a sibling of this node whose interests and assumptions
   // match the ones in the given node info.  If no sibling exists NULL
@@ -663,12 +671,11 @@ class RegExpNode: public ZoneObject {
   // processed before it is on a useable state.
   virtual RegExpNode* Clone() = 0;
 
-  inline void Bind(RegExpMacroAssembler* macro);
-
  private:
   Label label_;
   NodeInfo info_;
   SiblingList siblings_;
+  int variants_generated_;
 };
 
 
@@ -678,7 +685,6 @@ class SeqRegExpNode: public RegExpNode {
       : on_success_(on_success) { }
   RegExpNode* on_success() { return on_success_; }
   void set_on_success(RegExpNode* node) { on_success_ = node; }
-  virtual bool Emit(RegExpCompiler* compiler) { return false; }
  private:
   RegExpNode* on_success_;
 };
@@ -687,29 +693,31 @@ class SeqRegExpNode: public RegExpNode {
 class ActionNode: public SeqRegExpNode {
  public:
   enum Type {
-    STORE_REGISTER,
+    SET_REGISTER,
     INCREMENT_REGISTER,
     STORE_POSITION,
-    RESTORE_POSITION,
     BEGIN_SUBMATCH,
-    ESCAPE_SUBMATCH
+    POSITIVE_SUBMATCH_SUCCESS
   };
-  static ActionNode* StoreRegister(int reg, int val, RegExpNode* on_success);
+  static ActionNode* SetRegister(int reg, int val, RegExpNode* on_success);
   static ActionNode* IncrementRegister(int reg, RegExpNode* on_success);
   static ActionNode* StorePosition(int reg, RegExpNode* on_success);
-  static ActionNode* RestorePosition(int reg, RegExpNode* on_success);
-  static ActionNode* BeginSubmatch(int stack_pointer_reg,
-                                   int position_reg,
-                                   RegExpNode* on_success);
-  static ActionNode* EscapeSubmatch(int stack_pointer_reg,
-                                    bool and_restore_position,
-                                    int restore_reg,
-                                    RegExpNode* on_success);
+  static ActionNode* BeginSubmatch(
+      int stack_pointer_reg,
+      int position_reg,
+      RegExpNode* on_success);
+  static ActionNode* PositiveSubmatchSuccess(
+      int stack_pointer_reg,
+      int restore_reg,
+      RegExpNode* on_success);
   virtual void Accept(NodeVisitor* visitor);
-  virtual bool Emit(RegExpCompiler* compiler);
+  virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant);
   virtual RegExpNode* ExpandLocal(NodeInfo* info);
   virtual void ExpandChildren();
   virtual RegExpNode* PropagateForward(NodeInfo* info);
+  Type type() { return type_; }
+  // TODO(erikcorry): We should allow some action nodes in greedy loops.
+  virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; }
   virtual ActionNode* Clone() { return new ActionNode(*this); }
 
  private:
@@ -740,16 +748,12 @@ class ActionNode: public SeqRegExpNode {
 class TextNode: public SeqRegExpNode {
  public:
   TextNode(ZoneList<TextElement>* elms,
-           RegExpNode* on_success,
-           RegExpNode* on_failure)
+           RegExpNode* on_success)
       : SeqRegExpNode(on_success),
-        on_failure_(on_failure),
         elms_(elms) { }
   TextNode(RegExpCharacterClass* that,
-           RegExpNode* on_success,
-           RegExpNode* on_failure)
+           RegExpNode* on_success)
       : SeqRegExpNode(on_success),
-        on_failure_(on_failure),
         elms_(new ZoneList<TextElement>(1)) {
     elms_->Add(TextElement::CharClass(that));
   }
@@ -757,17 +761,20 @@ class TextNode: public SeqRegExpNode {
   virtual RegExpNode* PropagateForward(NodeInfo* info);
   virtual RegExpNode* ExpandLocal(NodeInfo* info);
   virtual void ExpandChildren();
-  RegExpNode* on_failure() { return on_failure_; }
-  virtual bool Emit(RegExpCompiler* compiler);
+  virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant);
   ZoneList<TextElement>* elements() { return elms_; }
   void MakeCaseIndependent();
-  virtual TextNode* Clone() { return new TextNode(*this); }
-
+  virtual int GreedyLoopTextLength();
+  virtual TextNode* Clone() {
+    TextNode* result = new TextNode(*this);
+    result->CalculateOffsets();
+    return result;
+  }
+  void CalculateOffsets();
  private:
   void ExpandAtomChildren(RegExpAtom* that);
   void ExpandCharClassChildren(RegExpCharacterClass* that);
 
-  RegExpNode* on_failure_;
   ZoneList<TextElement>* elms_;
 };
 
@@ -776,24 +783,20 @@ class BackReferenceNode: public SeqRegExpNode {
  public:
   BackReferenceNode(int start_reg,
                     int end_reg,
-                    RegExpNode* on_success,
-                    RegExpNode* on_failure)
+                    RegExpNode* on_success)
       : SeqRegExpNode(on_success),
-        on_failure_(on_failure),
         start_reg_(start_reg),
         end_reg_(end_reg) { }
   virtual void Accept(NodeVisitor* visitor);
-  RegExpNode* on_failure() { return on_failure_; }
   int start_register() { return start_reg_; }
   int end_register() { return end_reg_; }
-  virtual bool Emit(RegExpCompiler* compiler);
+  virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant);
   virtual RegExpNode* PropagateForward(NodeInfo* info);
   virtual RegExpNode* ExpandLocal(NodeInfo* info);
   virtual void ExpandChildren();
   virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); }
 
  private:
-  RegExpNode* on_failure_;
   int start_reg_;
   int end_reg_;
 };
@@ -801,22 +804,37 @@ class BackReferenceNode: public SeqRegExpNode {
 
 class EndNode: public RegExpNode {
  public:
-  enum Action { ACCEPT, BACKTRACK };
+  enum Action { ACCEPT, BACKTRACK, NEGATIVE_SUBMATCH_SUCCESS };
   explicit EndNode(Action action) : action_(action) { }
   virtual void Accept(NodeVisitor* visitor);
-  virtual bool Emit(RegExpCompiler* compiler);
+  virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant);
   virtual RegExpNode* PropagateForward(NodeInfo* info);
   virtual RegExpNode* ExpandLocal(NodeInfo* info);
   virtual void ExpandChildren();
-  virtual bool IsBacktrack() { return action_ == BACKTRACK; }
-  virtual bool GoTo(RegExpCompiler* compiler);
   virtual EndNode* Clone() { return new EndNode(*this); }
 
+ protected:
+  void EmitInfoChecks(RegExpMacroAssembler* macro, GenerationVariant* variant);
+
  private:
   Action action_;
 };
 
 
+class NegativeSubmatchSuccess: public EndNode {
+ public:
+  NegativeSubmatchSuccess(int stack_pointer_reg, int position_reg)
+      : EndNode(NEGATIVE_SUBMATCH_SUCCESS),
+        stack_pointer_register_(stack_pointer_reg),
+        current_position_register_(position_reg) { }
+  virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant);
+
+ private:
+  int stack_pointer_register_;
+  int current_position_register_;
+};
+
+
 class Guard: public ZoneObject {
  public:
   enum Relation { LT, GEQ };
@@ -851,17 +869,15 @@ class GuardedAlternative {
 
 class ChoiceNode: public RegExpNode {
  public:
-  explicit ChoiceNode(int expected_size, RegExpNode* on_failure)
-      : on_failure_(on_failure),
-        alternatives_(new ZoneList<GuardedAlternative>(expected_size)),
+  explicit ChoiceNode(int expected_size)
+      : alternatives_(new ZoneList<GuardedAlternative>(expected_size)),
         table_(NULL),
         being_calculated_(false) { }
   virtual void Accept(NodeVisitor* visitor);
   void AddAlternative(GuardedAlternative node) { alternatives()->Add(node); }
   ZoneList<GuardedAlternative>* alternatives() { return alternatives_; }
   DispatchTable* GetTable(bool ignore_case);
-  RegExpNode* on_failure() { return on_failure_; }
-  virtual bool Emit(RegExpCompiler* compiler);
+  virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant);
   virtual RegExpNode* PropagateForward(NodeInfo* info);
   virtual RegExpNode* ExpandLocal(NodeInfo* info);
   virtual void ExpandChildren();
@@ -870,19 +886,128 @@ class ChoiceNode: public RegExpNode {
   bool being_calculated() { return being_calculated_; }
   void set_being_calculated(bool b) { being_calculated_ = b; }
 
+ protected:
+  int GreedyLoopTextLength(GuardedAlternative *alternative);
+  ZoneList<GuardedAlternative>* alternatives_;
+
  private:
   friend class DispatchTableConstructor;
   friend class Analysis;
   void GenerateGuard(RegExpMacroAssembler* macro_assembler,
                      Guard *guard,
-                     Label* on_failure);
-  RegExpNode* on_failure_;
-  ZoneList<GuardedAlternative>* alternatives_;
+                     GenerationVariant* variant);
   DispatchTable* table_;
   bool being_calculated_;
 };
 
 
+class LoopChoiceNode: public ChoiceNode {
+ public:
+  explicit LoopChoiceNode(int expected_size) : ChoiceNode(expected_size) { }
+  virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant);
+  virtual LoopChoiceNode* Clone() { return new LoopChoiceNode(*this); }
+};
+
+
+// There are many ways to generate code for a node.  This class encapsulates
+// the current way we should be generating.  In other words it encapsulates
+// the current state of the code generator.
+class GenerationVariant {
+ public:
+  class DeferredAction {
+   public:
+    DeferredAction(ActionNode::Type type, int reg)
+        : type_(type), reg_(reg), next_(NULL) { }
+    DeferredAction* next() { return next_; }
+    int reg() { return reg_; }
+    ActionNode::Type type() { return type_; }
+   private:
+    ActionNode::Type type_;
+    int reg_;
+    DeferredAction* next_;
+    friend class GenerationVariant;
+  };
+
+  class DeferredCapture: public DeferredAction {
+   public:
+    DeferredCapture(int reg, GenerationVariant* variant)
+        : DeferredAction(ActionNode::STORE_POSITION, reg),
+          cp_offset_(variant->cp_offset()) { }
+    int cp_offset() { return cp_offset_; }
+   private:
+    int cp_offset_;
+    void set_cp_offset(int cp_offset) { cp_offset_ = cp_offset; }
+  };
+
+  class DeferredSetRegister :public DeferredAction {
+   public:
+    DeferredSetRegister(int reg, int value)
+        : DeferredAction(ActionNode::SET_REGISTER, reg),
+          value_(value) { }
+    int value() { return value_; }
+   private:
+    int value_;
+  };
+
+  class DeferredIncrementRegister: public DeferredAction {
+   public:
+    explicit DeferredIncrementRegister(int reg)
+        : DeferredAction(ActionNode::INCREMENT_REGISTER, reg) { }
+  };
+
+  explicit GenerationVariant(Label* backtrack)
+      : cp_offset_(0),
+        actions_(NULL),
+        backtrack_(backtrack),
+        stop_node_(NULL),
+        loop_label_(NULL) { }
+  GenerationVariant()
+      : cp_offset_(0),
+        actions_(NULL),
+        backtrack_(NULL),
+        stop_node_(NULL),
+        loop_label_(NULL) { }
+  bool Flush(RegExpCompiler* compiler, RegExpNode* successor);
+  int cp_offset() { return cp_offset_; }
+  DeferredAction* actions() { return actions_; }
+  bool is_trivial() {
+    return backtrack_ == NULL && actions_ == NULL && cp_offset_ == 0;
+  }
+  Label* backtrack() { return backtrack_; }
+  Label* loop_label() { return loop_label_; }
+  RegExpNode* stop_node() { return stop_node_; }
+  // These set methods should be used only on new GenerationVariants - the
+  // intention is that GenerationVariants are immutable after creation.
+  void add_action(DeferredAction* new_action) {
+    ASSERT(new_action->next_ == NULL);
+    new_action->next_ = actions_;
+    actions_ = new_action;
+  }
+  void set_cp_offset(int new_cp_offset) {
+    ASSERT(new_cp_offset >= cp_offset_);
+    cp_offset_ = new_cp_offset;
+  }
+  void set_backtrack(Label* backtrack) { backtrack_ = backtrack; }
+  void set_stop_node(RegExpNode* node) { stop_node_ = node; }
+  void set_loop_label(Label* label) { loop_label_ = label; }
+  bool mentions_reg(int reg);
+ private:
+  int FindAffectedRegisters(OutSet* affected_registers);
+  void PerformDeferredActions(RegExpMacroAssembler* macro,
+                               int max_register,
+                               OutSet& affected_registers);
+  void RestoreAffectedRegisters(RegExpMacroAssembler* macro,
+                                int max_register,
+                                OutSet& affected_registers);
+  void PushAffectedRegisters(RegExpMacroAssembler* macro,
+                             int max_register,
+                             OutSet& affected_registers);
+  int cp_offset_;
+  DeferredAction* actions_;
+  Label* backtrack_;
+  RegExpNode* stop_node_;
+  Label* loop_label_;
+};
 class NodeVisitor {
  public:
   virtual ~NodeVisitor() { }
@@ -956,7 +1081,8 @@ class RegExpEngine: public AllStatic {
   static Handle<FixedArray> Compile(RegExpParseResult* input,
                                     RegExpNode** node_return,
                                     bool ignore_case,
-                                    bool multiline);
+                                    bool multiline,
+                                    Handle<String> pattern);
   static void DotPrint(const char* label, RegExpNode* node, bool ignore_case);
 };
 
index b1aaaf5..f9839fb 100644 (file)
@@ -184,11 +184,14 @@ void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) {
 
 void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
                                                int cp_offset,
-                                               Label* on_failure) {
+                                               Label* on_failure,
+                                               bool check_end_of_string) {
   int byte_length = str.length() * char_size();
   int byte_offset = cp_offset * char_size();
-  __ cmp(Operand(edi), Immediate(-(byte_offset + byte_length)));
-  BranchOrBacktrack(greater, on_failure);
+  if (check_end_of_string) {
+    __ cmp(Operand(edi), Immediate(-(byte_offset + byte_length)));
+    BranchOrBacktrack(greater, on_failure);
+  }
 
   if (str.length() <= kMaxInlineStringTests) {
     for (int i = 0; i < str.length(); i++) {
@@ -233,10 +236,13 @@ void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
 }
 
 
-void RegExpMacroAssemblerIA32::CheckCurrentPosition(int register_index,
-                                                    Label* on_equal) {
-  __ cmp(edi, register_location(register_index));
-  BranchOrBacktrack(equal, on_equal);
+void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) {
+  Label fallthrough;
+  __ cmp(edi, Operand(esp, 0));
+  __ j(not_equal, &fallthrough);
+  __ add(Operand(esp), Immediate(4));  // Pop.
+  BranchOrBacktrack(no_condition, on_equal);
+  __ bind(&fallthrough);
 }
 
 
@@ -482,7 +488,7 @@ void RegExpMacroAssemblerIA32::Fail() {
 }
 
 
-Handle<Object> RegExpMacroAssemblerIA32::GetCode() {
+Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
   // Finalize code - write the entry point code now we know how many
   // registers we need.
 
@@ -521,7 +527,7 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode() {
   Label at_start;
   __ cmp(Operand(ebp, kAtStart), Immediate(0));
   __ j(not_equal, &at_start);
-  LoadCurrentCharToRegister(-1);  // Load previous char.
+  LoadCurrentCharacterUnchecked(-1);  // Load previous char.
   __ jmp(&start_label_);
   __ bind(&at_start);
   __ mov(current_character(), '\n');
@@ -562,7 +568,7 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode() {
                                        NULL,
                                        Code::ComputeFlags(Code::REGEXP),
                                        self_);
-  LOG(CodeCreateEvent("RegExp", *code, "(Compiled RegExp)"));
+  LOG(CodeCreateEvent("RegExp", *code, *(source->ToCString())));
   return Handle<Object>::cast(code);
 }
 
@@ -600,7 +606,7 @@ void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
   ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
   __ cmp(edi, -cp_offset * char_size());
   BranchOrBacktrack(greater_equal, on_end_of_input);
-  LoadCurrentCharToRegister(cp_offset);
+  LoadCurrentCharacterUnchecked(cp_offset);
 }
 
 
@@ -651,10 +657,17 @@ void RegExpMacroAssemblerIA32::Succeed() {
 }
 
 
-void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg) {
-  __ mov(register_location(reg), edi);
+void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg,
+                                                              int cp_offset) {
+  if (cp_offset == 0) {
+    __ mov(register_location(reg), edi);
+  } else {
+    __ lea(eax, Operand(edi, cp_offset));
+    __ mov(register_location(reg), eax);
+  }
 }
 
+
 void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
   __ mov(register_location(reg), esp);
 }
@@ -770,7 +783,7 @@ void RegExpMacroAssemblerIA32::CheckStackLimit() {
 }
 
 
-void RegExpMacroAssemblerIA32::LoadCurrentCharToRegister(int cp_offset) {
+void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset) {
   if (mode_ == ASCII) {
     __ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset));
     return;
index f8afe6f..78ab2bd 100644 (file)
@@ -47,8 +47,9 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
   virtual void CheckCharacterLT(uc16 limit, Label* on_less);
   virtual void CheckCharacters(Vector<const uc16> str,
                                int cp_offset,
-                               Label* on_failure);
-  virtual void CheckCurrentPosition(int register_index, Label* on_equal);
+                               Label* on_failure,
+                               bool check_end_of_string);
+  virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
   virtual void CheckNotAtStart(Label* on_not_at_start);
   virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
   virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
@@ -70,12 +71,14 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
                                    const Vector<Label*>& destinations);
   virtual void EmitOrLink(Label* label);
   virtual void Fail();
-  virtual Handle<Object> GetCode();
+  virtual Handle<Object> GetCode(Handle<String> source);
   virtual void GoTo(Label* label);
   virtual void IfRegisterGE(int reg, int comparand, Label* if_ge);
   virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
   virtual IrregexpImplementation Implementation();
   virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input);
+  virtual void LoadCurrentCharacterUnchecked(int cp_offset);
+
   virtual void PopCurrentPosition();
   virtual void PopRegister(int register_index);
   virtual void PushBacktrack(Label* label);
@@ -85,7 +88,7 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
   virtual void ReadStackPointerFromRegister(int reg);
   virtual void SetRegister(int register_index, int to);
   virtual void Succeed();
-  virtual void WriteCurrentPositionToRegister(int reg);
+  virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
   virtual void WriteStackPointerToRegister(int reg);
 
   template <typename T>
@@ -139,10 +142,6 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
   // is NULL, in which case it is a conditional Backtrack.
   void BranchOrBacktrack(Condition condition, Label* to);
 
-  // Read a character from input at the given offset from the current
-  // position.
-  void LoadCurrentCharToRegister(int cp_offset);
-
   // Load the address of a "constant buffer" (a slice of a byte array)
   // into a register. The address is computed from the ByteArray* address
   // and an offset. Uses no extra registers.
index b821788..44fa33c 100644 (file)
@@ -68,6 +68,7 @@ void RegExpMacroAssemblerIrregexp::Bind(Label* l) {
 
 
 void RegExpMacroAssemblerIrregexp::EmitOrLink(Label* l) {
+  if (l == NULL) l = &backtrack_;
   if (l->is_bound()) {
     Emit32(l->pos());
   } else {
@@ -95,11 +96,11 @@ void RegExpMacroAssemblerIrregexp::PushRegister(int register_index) {
 
 
 void RegExpMacroAssemblerIrregexp::WriteCurrentPositionToRegister(
-    int register_index) {
+    int register_index, int cp_offset) {
   ASSERT(register_index >= 0);
   Emit(BC_SET_REGISTER_TO_CP);
   Emit(register_index);
-  Emit32(0);  // Current position offset.
+  Emit32(cp_offset);  // Current position offset.
 }
 
 
@@ -187,11 +188,10 @@ void RegExpMacroAssemblerIrregexp::AdvanceCurrentPosition(int by) {
 }
 
 
-void RegExpMacroAssemblerIrregexp::CheckCurrentPosition(
-  int register_index,
-  Label* on_equal) {
-  // TODO(erikcorry): Implement.
-  UNIMPLEMENTED();
+void RegExpMacroAssemblerIrregexp::CheckGreedyLoop(
+      Label* on_tos_equals_current_position) {
+  Emit(BC_CHECK_GREEDY);
+  EmitOrLink(on_tos_equals_current_position);
 }
 
 
@@ -203,6 +203,13 @@ void RegExpMacroAssemblerIrregexp::LoadCurrentCharacter(int cp_offset,
 }
 
 
+void RegExpMacroAssemblerIrregexp::LoadCurrentCharacterUnchecked(
+      int cp_offset) {
+  Emit(BC_LOAD_CURRENT_CHAR_UNCHECKED);
+  Emit32(cp_offset);
+}
+
+
 void RegExpMacroAssemblerIrregexp::CheckCharacterLT(uc16 limit,
                                                     Label* on_less) {
   Emit(BC_CHECK_LT);
@@ -263,7 +270,7 @@ void RegExpMacroAssemblerIrregexp::CheckNotCharacterAfterMinusOr(
 
 
 void RegExpMacroAssemblerIrregexp::CheckNotBackReference(int start_reg,
-                                                     Label* on_not_equal) {
+                                                         Label* on_not_equal) {
   Emit(BC_CHECK_NOT_BACK_REF);
   Emit(start_reg);
   EmitOrLink(on_not_equal);
@@ -323,11 +330,19 @@ void RegExpMacroAssemblerIrregexp::DispatchHighByteMap(
 void RegExpMacroAssemblerIrregexp::CheckCharacters(
   Vector<const uc16> str,
   int cp_offset,
-  Label* on_failure) {
+  Label* on_failure,
+  bool check_end_of_string) {
+  // It is vital that this loop is backwards due to the unchecked character
+  // load below.
   for (int i = str.length() - 1; i >= 0; i--) {
-    Emit(BC_LOAD_CURRENT_CHAR);
-    Emit32(cp_offset + i);
-    EmitOrLink(on_failure);
+    if (check_end_of_string && i == str.length() - 1) {
+      Emit(BC_LOAD_CURRENT_CHAR);
+      Emit32(cp_offset + i);
+      EmitOrLink(on_failure);
+    } else {
+      Emit(BC_LOAD_CURRENT_CHAR_UNCHECKED);
+      Emit32(cp_offset + i);
+    }
     Emit(BC_CHECK_NOT_CHAR);
     Emit16(str[i]);
     EmitOrLink(on_failure);
@@ -357,7 +372,9 @@ void RegExpMacroAssemblerIrregexp::IfRegisterGE(int register_index,
 }
 
 
-Handle<Object> RegExpMacroAssemblerIrregexp::GetCode() {
+Handle<Object> RegExpMacroAssemblerIrregexp::GetCode(Handle<String> source) {
+  Bind(&backtrack_);
+  Emit(BC_POP_BT);
   Handle<ByteArray> array = Factory::NewByteArray(length());
   Copy(array->GetDataStartAddress());
   return array;
index 77d18e1..722e779 100644 (file)
@@ -62,14 +62,16 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
   virtual void PushRegister(int register_index);
   virtual void AdvanceRegister(int reg, int by);  // r[reg] += by.
   virtual void SetRegister(int register_index, int to);
-  virtual void WriteCurrentPositionToRegister(int reg);
+  virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
   virtual void ReadCurrentPositionFromRegister(int reg);
   virtual void WriteStackPointerToRegister(int reg);
   virtual void ReadStackPointerFromRegister(int reg);
   virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input);
+  virtual void LoadCurrentCharacterUnchecked(int cp_offset);
   virtual void CheckCharacterLT(uc16 limit, Label* on_less);
   virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
   virtual void CheckCharacter(uc16 c, Label* on_equal);
+  virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
   virtual void CheckNotAtStart(Label* on_not_at_start);
   virtual void CheckNotCharacter(uc16 c, Label* on_not_equal);
   virtual void CheckNotCharacterAfterOr(uc16 c, uc16 mask, Label* on_not_equal);
@@ -82,8 +84,8 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
   virtual void CheckNotRegistersEqual(int reg1, int reg2, Label* on_not_equal);
   virtual void CheckCharacters(Vector<const uc16> str,
                                int cp_offset,
-                               Label* on_failure);
-  virtual void CheckCurrentPosition(int register_index, Label* on_equal);
+                               Label* on_failure,
+                               bool check_end_of_string);
   virtual void CheckBitmap(uc16 start, Label* bitmap, Label* on_zero);
   virtual void DispatchHalfNibbleMap(uc16 start,
                                      Label* half_nibble_map,
@@ -98,7 +100,7 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
   virtual void IfRegisterGE(int register_index, int comparand, Label* if_ge);
 
   virtual IrregexpImplementation Implementation();
-  virtual Handle<Object> GetCode();
+  virtual Handle<Object> GetCode(Handle<String> source);
  private:
   void Expand();
   // Code and bitmap emission.
@@ -109,14 +111,13 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
   int length();
   void Copy(Address a);
 
-
-
   // The buffer into which code and relocation info are generated.
   Vector<byte> buffer_;
   // The program counter.
   int pc_;
   // True if the assembler owns the buffer, false if buffer is external.
   bool own_buffer_;
+  Label backtrack_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(RegExpMacroAssemblerIrregexp);
 };
index 80dff25..fc3629c 100644 (file)
@@ -64,6 +64,12 @@ void RegExpMacroAssemblerTracer::AdvanceCurrentPosition(int by) {
 }
 
 
+void RegExpMacroAssemblerTracer::CheckGreedyLoop(Label* label) {
+  PrintF(" CheckGreedyLoop(label[%08x]);\n\n", label);
+  assembler_->CheckGreedyLoop(label);
+}
+
+
 void RegExpMacroAssemblerTracer::PopCurrentPosition() {
   PrintF(" PopCurrentPosition();\n");
   assembler_->PopCurrentPosition();
@@ -130,9 +136,12 @@ void RegExpMacroAssemblerTracer::SetRegister(int register_index, int to) {
 }
 
 
-void RegExpMacroAssemblerTracer::WriteCurrentPositionToRegister(int reg) {
-  PrintF(" WriteCurrentPositionToRegister(register=%d);\n", reg);
-  assembler_->WriteCurrentPositionToRegister(reg);
+void RegExpMacroAssemblerTracer::WriteCurrentPositionToRegister(int reg,
+                                                                int cp_offset) {
+  PrintF(" WriteCurrentPositionToRegister(register=%d,cp_offset=%d);\n",
+         reg,
+         cp_offset);
+  assembler_->WriteCurrentPositionToRegister(reg, cp_offset);
 }
 
 
@@ -156,12 +165,20 @@ void RegExpMacroAssemblerTracer::ReadStackPointerFromRegister(int reg) {
 
 void RegExpMacroAssemblerTracer::LoadCurrentCharacter(int cp_offset,
                                                       Label* on_end_of_input) {
-  PrintF(" LoadCurrentCharacter(cp_offset=%d, label[%08x]);\n", cp_offset,
+  PrintF(" LoadCurrentCharacter(cp_offset=%d, label[%08x]);\n",
+         cp_offset,
          on_end_of_input);
   assembler_->LoadCurrentCharacter(cp_offset, on_end_of_input);
 }
 
 
+void RegExpMacroAssemblerTracer::LoadCurrentCharacterUnchecked(int cp_offset) {
+  PrintF(" LoadCurrentCharacterUnchecked(cp_offset=%d);\n",
+         cp_offset);
+  assembler_->LoadCurrentCharacterUnchecked(cp_offset);
+}
+
+
 void RegExpMacroAssemblerTracer::CheckCharacterLT(uc16 limit, Label* on_less) {
   PrintF(" CheckCharacterLT(c='u%04x', label[%08x]);\n", limit, on_less);
   assembler_->CheckCharacterLT(limit, on_less);
@@ -242,21 +259,15 @@ void RegExpMacroAssemblerTracer::CheckNotRegistersEqual(int reg1,
 
 void RegExpMacroAssemblerTracer::CheckCharacters(Vector<const uc16> str,
                                                  int cp_offset,
-                                                 Label* on_failure) {
-  PrintF(" CheckCharacters(str=\"");
+                                                 Label* on_failure,
+                                                 bool check_end_of_string) {
+  PrintF(" %s(str=\"",
+         check_end_of_string ? "CheckCharacters" : "CheckCharactersUnchecked");
   for (int i = 0; i < str.length(); i++) {
     PrintF("u%04x", str[i]);
   }
   PrintF("\", cp_offset=%d, label[%08x])\n", cp_offset, on_failure);
-  assembler_->CheckCharacters(str, cp_offset, on_failure);
-}
-
-
-void RegExpMacroAssemblerTracer::CheckCurrentPosition(int register_index,
-                                                      Label* on_equal) {
-  PrintF(" CheckCurrentPosition(register=%d, label[%08x]);\n", register_index,
-         on_equal);
-  assembler_->CheckCurrentPosition(register_index, on_equal);
+  assembler_->CheckCharacters(str, cp_offset, on_failure, check_end_of_string);
 }
 
 
@@ -334,9 +345,9 @@ RegExpMacroAssembler::IrregexpImplementation
 }
 
 
-Handle<Object> RegExpMacroAssemblerTracer::GetCode() {
-  PrintF(" GetCode();\n");
-  return assembler_->GetCode();
+Handle<Object> RegExpMacroAssemblerTracer::GetCode(Handle<String> source) {
+  PrintF(" GetCode(%s);\n", *(source->ToCString()));
+  return assembler_->GetCode(source);
 }
 
 }}  // namespace v8::internal
index 3488082..88d4cc1 100644 (file)
@@ -47,10 +47,9 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
   virtual void CheckCharacters(
       Vector<const uc16> str,
       int cp_offset,
-      Label* on_failure);
-  virtual void CheckCurrentPosition(
-      int register_index,
-      Label* on_equal);
+      Label* on_failure,
+      bool check_end_of_string);
+  virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
   virtual void CheckNotAtStart(Label* on_not_at_start);
   virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
   virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
@@ -77,12 +76,13 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
       const Vector<Label*>& destinations);
   virtual void EmitOrLink(Label* label);
   virtual void Fail();
-  virtual Handle<Object> GetCode();
+  virtual Handle<Object> GetCode(Handle<String> source);
   virtual void GoTo(Label* label);
   virtual void IfRegisterGE(int reg, int comparand, Label* if_ge);
   virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
   virtual IrregexpImplementation Implementation();
   virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input);
+  virtual void LoadCurrentCharacterUnchecked(int cp_offset);
   virtual void PopCurrentPosition();
   virtual void PopRegister(int register_index);
   virtual void PushBacktrack(Label* label);
@@ -92,7 +92,7 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
   virtual void ReadStackPointerFromRegister(int reg);
   virtual void SetRegister(int register_index, int to);
   virtual void Succeed();
-  virtual void WriteCurrentPositionToRegister(int reg);
+  virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
   virtual void WriteStackPointerToRegister(int reg);
  private:
   RegExpMacroAssembler* assembler_;
index 8cbd274..5ed1523 100644 (file)
@@ -62,19 +62,17 @@ class RegExpMacroAssembler {
   virtual void CheckCharacterGT(uc16 limit, Label* on_greater) = 0;
   virtual void CheckCharacterLT(uc16 limit, Label* on_less) = 0;
   // Check the current character for a match with a literal string.  If we
-  // fail to match then goto the on_failure label.  End of input always
-  // matches.  If the label is NULL then we should pop a backtrack address off
-  // the stack abnd go to that.
+  // fail to match then goto the on_failure label.  If check_eos is set then
+  // the end of input always fails.  If check_eos is clear then it is the
+  // caller's responsibility to ensure that the end of string is not hit.
+  // If the label is NULL then we should pop a backtrack address off
+  // the stack and go to that.
   virtual void CheckCharacters(
       Vector<const uc16> str,
       int cp_offset,
-      Label* on_failure) = 0;
-  // Check the current input position against a register.  If the register is
-  // equal to the current position then go to the label.  If the label is NULL
-  // then backtrack instead.
-  virtual void CheckCurrentPosition(
-      int register_index,
-      Label* on_equal) = 0;
+      Label* on_failure,
+      bool check_eos) = 0;
+  virtual void CheckGreedyLoop(Label* on_tos_equals_current_position) = 0;
   virtual void CheckNotAtStart(Label* on_not_at_start) = 0;
   virtual void CheckNotBackReference(int start_reg, Label* on_no_match) = 0;
   virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
@@ -115,7 +113,7 @@ class RegExpMacroAssembler {
       const Vector<Label*>& destinations) = 0;
   virtual void EmitOrLink(Label* label) = 0;
   virtual void Fail() = 0;
-  virtual Handle<Object> GetCode() = 0;
+  virtual Handle<Object> GetCode(Handle<String> source) = 0;
   virtual void GoTo(Label* label) = 0;
   // Check whether a register is >= a given constant and go to a label if it
   // is.  Backtracks instead if the label is NULL.
@@ -125,6 +123,7 @@ class RegExpMacroAssembler {
   virtual void IfRegisterLT(int reg, int comparand, Label* if_lt) = 0;
   virtual IrregexpImplementation Implementation() = 0;
   virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input) = 0;
+  virtual void LoadCurrentCharacterUnchecked(int cp_offset) = 0;
   virtual void PopCurrentPosition() = 0;
   virtual void PopRegister(int register_index) = 0;
   virtual void PushBacktrack(Label* label) = 0;
@@ -134,7 +133,7 @@ class RegExpMacroAssembler {
   virtual void ReadStackPointerFromRegister(int reg) = 0;
   virtual void SetRegister(int register_index, int to) = 0;
   virtual void Succeed() = 0;
-  virtual void WriteCurrentPositionToRegister(int reg) = 0;
+  virtual void WriteCurrentPositionToRegister(int reg, int cp_offset) = 0;
   virtual void WriteStackPointerToRegister(int reg) = 0;
 
  private:
index cf0733e..4bd3222 100644 (file)
@@ -362,7 +362,8 @@ static RegExpNode* Compile(const char* input, bool multiline) {
   if (!v8::internal::ParseRegExp(&reader, multiline, &result))
     return NULL;
   RegExpNode* node = NULL;
-  RegExpEngine::Compile(&result, &node, false, multiline);
+  Handle<String> pattern = Factory::NewStringFromUtf8(CStrVector(input));
+  RegExpEngine::Compile(&result, &node, false, multiline, pattern);
   return node;
 }
 
@@ -520,16 +521,16 @@ TEST(MacroAssembler) {
   m.Fail();
   m.Bind(&start);
   m.PushBacktrack(&fail2);
-  m.CheckCharacters(foo, 0, &fail);
-  m.WriteCurrentPositionToRegister(0);
+  m.CheckCharacters(foo, 0, &fail, true);
+  m.WriteCurrentPositionToRegister(0, 0);
   m.PushCurrentPosition();
   m.AdvanceCurrentPosition(3);
-  m.WriteCurrentPositionToRegister(1);
+  m.WriteCurrentPositionToRegister(1, 0);
   m.PopCurrentPosition();
   m.AdvanceCurrentPosition(1);
-  m.WriteCurrentPositionToRegister(2);
+  m.WriteCurrentPositionToRegister(2, 0);
   m.AdvanceCurrentPosition(1);
-  m.WriteCurrentPositionToRegister(3);
+  m.WriteCurrentPositionToRegister(3, 0);
   m.Succeed();
 
   m.Bind(&fail);
@@ -542,7 +543,8 @@ TEST(MacroAssembler) {
 
   v8::HandleScope scope;
 
-  Handle<ByteArray> array = Handle<ByteArray>::cast(m.GetCode());
+  Handle<String> source = Factory::NewStringFromAscii(CStrVector("^f(o)o"));
+  Handle<ByteArray> array = Handle<ByteArray>::cast(m.GetCode(source));
   int captures[5];
 
   Handle<String> f1 =
@@ -576,7 +578,8 @@ TEST(MacroAssemblerIA32Success) {
 
   m.Succeed();
 
-  Handle<Object> code_object = m.GetCode();
+  Handle<String> source = Factory::NewStringFromAscii(CStrVector(""));
+  Handle<Object> code_object = m.GetCode(source);
   Handle<Code> code = Handle<Code>::cast(code_object);
 
   int captures[4] = {42, 37, 87, 117};
@@ -614,15 +617,16 @@ TEST(MacroAssemblerIA32Simple) {
   Vector<const uc16> foo(foo_chars, 3);
 
   Label fail;
-  m.CheckCharacters(foo, 0, &fail);
-  m.WriteCurrentPositionToRegister(0);
+  m.CheckCharacters(foo, 0, &fail, true);
+  m.WriteCurrentPositionToRegister(0, 0);
   m.AdvanceCurrentPosition(3);
-  m.WriteCurrentPositionToRegister(1);
+  m.WriteCurrentPositionToRegister(1, 0);
   m.Succeed();
   m.Bind(&fail);
   m.Fail();
 
-  Handle<Object> code_object = m.GetCode();
+  Handle<String> source = Factory::NewStringFromAscii(CStrVector("^foo"));
+  Handle<Object> code_object = m.GetCode(source);
   Handle<Code> code = Handle<Code>::cast(code_object);
 
   int captures[4] = {42, 37, 87, 117};
@@ -675,15 +679,16 @@ TEST(MacroAssemblerIA32SimpleUC16) {
   Vector<const uc16> foo(foo_chars, 3);
 
   Label fail;
-  m.CheckCharacters(foo, 0, &fail);
-  m.WriteCurrentPositionToRegister(0);
+  m.CheckCharacters(foo, 0, &fail, true);
+  m.WriteCurrentPositionToRegister(0, 0);
   m.AdvanceCurrentPosition(3);
-  m.WriteCurrentPositionToRegister(1);
+  m.WriteCurrentPositionToRegister(1, 0);
   m.Succeed();
   m.Bind(&fail);
   m.Fail();
 
-  Handle<Object> code_object = m.GetCode();
+  Handle<String> source = Factory::NewStringFromAscii(CStrVector("^foo"));
+  Handle<Object> code_object = m.GetCode(source);
   Handle<Code> code = Handle<Code>::cast(code_object);
 
   int captures[4] = {42, 37, 87, 117};
@@ -735,9 +740,6 @@ TEST(MacroAssemblerIA32Backtrack) {
 
   RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 0);
 
-  uc16 foo_chars[3] = {'f', 'o', 'o'};
-  Vector<const uc16> foo(foo_chars, 3);
-
   Label fail;
   Label backtrack;
   m.LoadCurrentCharacter(10, &fail);
@@ -749,7 +751,8 @@ TEST(MacroAssemblerIA32Backtrack) {
   m.Bind(&backtrack);
   m.Fail();
 
-  Handle<Object> code_object = m.GetCode();
+  Handle<String> source = Factory::NewStringFromAscii(CStrVector(".........."));
+  Handle<Object> code_object = m.GetCode(source);
   Handle<Code> code = Handle<Code>::cast(code_object);
 
   Handle<String> input = Factory::NewStringFromAscii(CStrVector("foofoo"));
@@ -778,9 +781,9 @@ TEST(MacroAssemblerIA32BackReference) {
 
   RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 3);
 
-  m.WriteCurrentPositionToRegister(0);
+  m.WriteCurrentPositionToRegister(0, 0);
   m.AdvanceCurrentPosition(2);
-  m.WriteCurrentPositionToRegister(1);
+  m.WriteCurrentPositionToRegister(1, 0);
   Label nomatch;
   m.CheckNotBackReference(0, &nomatch);
   m.Fail();
@@ -788,12 +791,13 @@ TEST(MacroAssemblerIA32BackReference) {
   m.AdvanceCurrentPosition(2);
   Label missing_match;
   m.CheckNotBackReference(0, &missing_match);
-  m.WriteCurrentPositionToRegister(2);
+  m.WriteCurrentPositionToRegister(2, 0);
   m.Succeed();
   m.Bind(&missing_match);
   m.Fail();
 
-  Handle<Object> code_object = m.GetCode();
+  Handle<String> source = Factory::NewStringFromAscii(CStrVector("^(..)..\1"));
+  Handle<Object> code_object = m.GetCode(source);
   Handle<Code> code = Handle<Code>::cast(code_object);
 
   Handle<String> input = Factory::NewStringFromAscii(CStrVector("fooofo"));
@@ -826,9 +830,6 @@ TEST(MacroAssemblerIA32AtStart) {
 
   RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 0);
 
-  uc16 foo_chars[3] = {'f', 'o', 'o'};
-  Vector<const uc16> foo(foo_chars, 3);
-
   Label not_at_start, newline, fail;
   m.CheckNotAtStart(&not_at_start);
   // Check that prevchar = '\n' and current = 'f'.
@@ -850,7 +851,8 @@ TEST(MacroAssemblerIA32AtStart) {
   m.CheckNotCharacter('b', &fail);
   m.Succeed();
 
-  Handle<Object> code_object = m.GetCode();
+  Handle<String> source = Factory::NewStringFromAscii(CStrVector("(^f|ob)"));
+  Handle<Object> code_object = m.GetCode(source);
   Handle<Code> code = Handle<Code>::cast(code_object);
 
   Handle<String> input = Factory::NewStringFromAscii(CStrVector("foobar"));
@@ -893,10 +895,10 @@ TEST(MacroAssemblerIA32BackRefNoCase) {
 
   Label fail, succ;
 
-  m.WriteCurrentPositionToRegister(0);
-  m.WriteCurrentPositionToRegister(2);
+  m.WriteCurrentPositionToRegister(0, 0);
+  m.WriteCurrentPositionToRegister(2, 0);
   m.AdvanceCurrentPosition(3);
-  m.WriteCurrentPositionToRegister(3);
+  m.WriteCurrentPositionToRegister(3, 0);
   m.CheckNotBackReferenceIgnoreCase(2, &fail);  // Match "AbC".
   m.CheckNotBackReferenceIgnoreCase(2, &fail);  // Match "ABC".
   Label expected_fail;
@@ -910,10 +912,12 @@ TEST(MacroAssemblerIA32BackRefNoCase) {
   m.Fail();
 
   m.Bind(&succ);
-  m.WriteCurrentPositionToRegister(1);
+  m.WriteCurrentPositionToRegister(1, 0);
   m.Succeed();
 
-  Handle<Object> code_object = m.GetCode();
+  Handle<String> source =
+      Factory::NewStringFromAscii(CStrVector("^(abc)\1\1(?!\1)...(?!\1)"));
+  Handle<Object> code_object = m.GetCode(source);
   Handle<Code> code = Handle<Code>::cast(code_object);
 
   Handle<String> input =
@@ -955,13 +959,13 @@ TEST(MacroAssemblerIA32Registers) {
   enum registers { out1, out2, out3, out4, out5, sp, loop_cnt };
   Label fail;
   Label backtrack;
-  m.WriteCurrentPositionToRegister(out1);  // Output: [0]
+  m.WriteCurrentPositionToRegister(out1, 0);  // Output: [0]
   m.PushRegister(out1);
   m.PushBacktrack(&backtrack);
   m.WriteStackPointerToRegister(sp);
   // Fill stack and registers
   m.AdvanceCurrentPosition(2);
-  m.WriteCurrentPositionToRegister(out1);
+  m.WriteCurrentPositionToRegister(out1, 0);
   m.PushRegister(out1);
   m.PushBacktrack(&fail);
   // Drop backtrack stack frames.
@@ -977,7 +981,7 @@ TEST(MacroAssemblerIA32Registers) {
   m.PopRegister(out1);
   m.ReadCurrentPositionFromRegister(out1);
   m.AdvanceCurrentPosition(3);
-  m.WriteCurrentPositionToRegister(out2);  // [0,3]
+  m.WriteCurrentPositionToRegister(out2, 0);  // [0,3]
 
   Label loop;
   m.SetRegister(loop_cnt, 0);  // loop counter
@@ -985,7 +989,7 @@ TEST(MacroAssemblerIA32Registers) {
   m.AdvanceRegister(loop_cnt, 1);
   m.AdvanceCurrentPosition(1);
   m.IfRegisterLT(loop_cnt, 3, &loop);
-  m.WriteCurrentPositionToRegister(out3);  // [0,3,6]
+  m.WriteCurrentPositionToRegister(out3, 0);  // [0,3,6]
 
   Label loop2;
   m.SetRegister(loop_cnt, 2);  // loop counter
@@ -993,24 +997,29 @@ TEST(MacroAssemblerIA32Registers) {
   m.AdvanceRegister(loop_cnt, -1);
   m.AdvanceCurrentPosition(1);
   m.IfRegisterGE(loop_cnt, 0, &loop2);
-  m.WriteCurrentPositionToRegister(out4);  // [0,3,6,9]
+  m.WriteCurrentPositionToRegister(out4, 0);  // [0,3,6,9]
 
   Label loop3;
   Label exit_loop3;
+  m.PushRegister(out4);
+  m.PushRegister(out4);
   m.ReadCurrentPositionFromRegister(out3);
   m.Bind(&loop3);
   m.AdvanceCurrentPosition(1);
-  m.CheckCurrentPosition(out4, &exit_loop3);
+  m.CheckGreedyLoop(&exit_loop3);
   m.GoTo(&loop3);
   m.Bind(&exit_loop3);
-  m.WriteCurrentPositionToRegister(out5);  // [0,3,6,9,9]
+  m.PopCurrentPosition();
+  m.WriteCurrentPositionToRegister(out5, 0);  // [0,3,6,9,9]
 
   m.Succeed();
 
   m.Bind(&fail);
   m.Fail();
 
-  Handle<Object> code_object = m.GetCode();
+  Handle<String> source =
+      Factory::NewStringFromAscii(CStrVector("<loop test>"));
+  Handle<Object> code_object = m.GetCode(source);
   Handle<Code> code = Handle<Code>::cast(code_object);
 
   // String long enough for test (content doesn't matter).
@@ -1291,5 +1300,5 @@ TEST(CharClassDifference) {
 
 TEST(Graph) {
   V8::Initialize(NULL);
-  Execute("\\b\\w", false, true);
+  Execute("(?=[d#.])", false, true);
 }
index 0ed72e6..46374cc 100644 (file)
@@ -286,3 +286,23 @@ for (var i = 0; i < 128; i++) {
 }
 
 assertFalse(/f(o)$\1/.test('foo'), "backref detects at_end");
+
+// Check that we don't read past the end of the string.
+assertFalse(/f/.test('b'));
+assertFalse(/[abc]f/.test('x'));
+assertFalse(/[abc]f/.test('xa'));
+assertFalse(/[abc]</.test('x'));
+assertFalse(/[abc]</.test('xa'));
+assertFalse(/f/i.test('b'));
+assertFalse(/[abc]f/i.test('x'));
+assertFalse(/[abc]f/i.test('xa'));
+assertFalse(/[abc]</i.test('x'));
+assertFalse(/[abc]</i.test('xa'));
+assertFalse(/f[abc]/.test('x'));
+assertFalse(/f[abc]/.test('xa'));
+assertFalse(/<[abc]/.test('x'));
+assertFalse(/<[abc]/.test('xa'));
+assertFalse(/f[abc]/i.test('x'));
+assertFalse(/f[abc]/i.test('xa'));
+assertFalse(/<[abc]/i.test('x'));
+assertFalse(/<[abc]/i.test('xa'));