Bug 976446 - Add port of irregexp regexp engine, and use by default, r=jandem.
authorBrian Hackett <bhackett1024@gmail.com>
Thu, 15 May 2014 16:48:21 -0700
changeset 202635 43acd23f5a98dda2632dacc0edebac38ff82ec6e
parent 202634 4e38abbbd329d0d38afcdcc1d79981bd35e02709
child 202636 f396da6ddff2996bc2844fa5af26ac2abe07dc72
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs976446
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 976446 - Add port of irregexp regexp engine, and use by default, r=jandem.
dom/workers/RuntimeService.cpp
js/src/builtin/RegExp.cpp
js/src/builtin/RegExp.h
js/src/configure.in
js/src/ds/LifoAlloc.h
js/src/frontend/Parser.cpp
js/src/frontend/TokenStream.cpp
js/src/irregexp/NativeRegExpMacroAssembler.cpp
js/src/irregexp/NativeRegExpMacroAssembler.h
js/src/irregexp/RegExpAST.cpp
js/src/irregexp/RegExpAST.h
js/src/irregexp/RegExpBytecode.h
js/src/irregexp/RegExpEngine.cpp
js/src/irregexp/RegExpEngine.h
js/src/irregexp/RegExpInterpreter.cpp
js/src/irregexp/RegExpMacroAssembler.cpp
js/src/irregexp/RegExpMacroAssembler.h
js/src/irregexp/RegExpParser.cpp
js/src/irregexp/RegExpParser.h
js/src/irregexp/RegExpStack.cpp
js/src/irregexp/RegExpStack.h
js/src/jit-test/tests/basic/bug576837-regexp.js
js/src/jit-test/tests/basic/bug976446.js
js/src/jit-test/tests/basic/regexp-match-limit.js
js/src/jit-test/tests/basic/testSlowNativeBail.js
js/src/jit/AsmJS.cpp
js/src/jit/IonAllocPolicy.h
js/src/jit/IonLinker.h
js/src/jit/JitCommon.h
js/src/jit/Label.h
js/src/jit/arm/MacroAssembler-arm.cpp
js/src/jit/arm/MacroAssembler-arm.h
js/src/jit/arm/Simulator-arm.cpp
js/src/jit/shared/Assembler-shared.h
js/src/jit/shared/MacroAssembler-x86-shared.h
js/src/jit/x64/MacroAssembler-x64.h
js/src/jit/x86/MacroAssembler-x86.h
js/src/js.msg
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscompartment.h
js/src/jsstr.cpp
js/src/moz.build
js/src/shell/js.cpp
js/src/tests/js1_5/Exceptions/regress-332472.js
js/src/tests/js1_5/Regress/regress-230216-2.js
js/src/tests/js1_5/Regress/regress-280769-1.js
js/src/tests/js1_5/Regress/regress-280769-5.js
js/src/tests/js1_5/Regress/regress-440926.js
js/src/vm/MatchPairs.h
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/Runtime.cpp
js/src/vm/Runtime.h
js/src/vm/SelfHosting.cpp
js/src/vm/StructuredClone.cpp
js/src/vm/TraceLogging.cpp
js/src/vm/TraceLogging.h
js/src/vm/Unicode.h
js/src/yarr/YarrJIT.cpp
js/src/yarr/YarrJIT.h
js/src/yarr/wtfbridge.h
js/xpconnect/src/XPCJSRuntime.cpp
modules/libpref/src/init/all.js
toolkit/content/license.html
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -335,16 +335,19 @@ LoadRuntimeAndContextOptions(const char*
     runtimeOptions.setAsmJS(true);
   }
   if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("baselinejit"))) {
     runtimeOptions.setBaseline(true);
   }
   if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("ion"))) {
     runtimeOptions.setIon(true);
   }
+  if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("native_regexp"))) {
+    runtimeOptions.setNativeRegExp(true);
+  }
 
   // Common options.
   JS::ContextOptions commonContextOptions = kRequiredContextOptions;
   if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("strict"))) {
     commonContextOptions.setExtraWarnings(true);
   }
   if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("werror"))) {
     commonContextOptions.setWerror(true);
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -3,16 +3,20 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "builtin/RegExp.h"
 
 #include "jscntxt.h"
 
+#ifndef JS_YARR
+#include "irregexp/RegExpParser.h"
+#endif
+
 #include "vm/RegExpStatics.h"
 #include "vm/StringBuffer.h"
 
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::types;
 
@@ -89,30 +93,33 @@ static RegExpRunStatus
 ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, RegExpShared &re,
                   Handle<JSLinearString*> input, const jschar *chars, size_t length,
                   size_t *lastIndex, MatchConduit &matches)
 {
     RegExpRunStatus status;
 
     /* Switch between MatchOnly and IncludeSubpatterns modes. */
     if (matches.isPair) {
+#ifdef JS_YARR
         size_t lastIndex_orig = *lastIndex;
         /* Only one MatchPair slot provided: execute short-circuiting regexp. */
         status = re.executeMatchOnly(cx, chars, length, lastIndex, *matches.u.pair);
         if (status == RegExpRunStatus_Success && res)
             res->updateLazily(cx, input, &re, lastIndex_orig);
+#else
+        MOZ_CRASH();
+#endif
     } else {
         /* Vector of MatchPairs provided: execute full regexp. */
         status = re.execute(cx, chars, length, lastIndex, *matches.u.pairs);
         if (status == RegExpRunStatus_Success && res) {
             if (!res->updateFromMatchPairs(cx, input, *matches.u.pairs))
                 return RegExpRunStatus_Error;
         }
     }
-
     return status;
 }
 
 /* Legacy ExecuteRegExp behavior is baked into the JSAPI. */
 bool
 js::ExecuteRegExpLegacy(JSContext *cx, RegExpStatics *res, RegExpObject &reobj,
                         Handle<JSLinearString*> input_, const jschar *chars, size_t length,
                         size_t *lastIndex, bool test, MutableHandleValue rval)
@@ -278,18 +285,26 @@ CompileRegExpObject(JSContext *cx, RegEx
         if (!ParseRegExpFlags(cx, flagStr, &flags))
             return false;
     }
 
     RootedAtom escapedSourceStr(cx, EscapeNakedForwardSlashes(cx, source));
     if (!escapedSourceStr)
         return false;
 
-    if (!js::RegExpShared::checkSyntax(cx, nullptr, escapedSourceStr))
+#ifdef JS_YARR
+    if (!RegExpShared::checkSyntax(cx, nullptr, escapedSourceStr))
         return false;
+#else // JS_YARR
+    CompileOptions options(cx);
+    frontend::TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr);
+
+    if (!irregexp::ParsePatternSyntax(dummyTokenStream, cx->tempLifoAlloc(), escapedSourceStr->chars(), escapedSourceStr->length()))
+        return false;
+#endif // JS_YARR
 
     RegExpStatics *res = cx->global()->getRegExpStatics(cx);
     if (!res)
         return false;
     RegExpObject *reobj = builder.build(escapedSourceStr, RegExpFlag(flags | res->getFlags()));
     if (!reobj)
         return false;
 
@@ -673,29 +688,39 @@ js::regexp_exec_no_statics(JSContext *cx
 
     return regexp_exec_impl(cx, regexp, string, DontUpdateRegExpStatics, args.rval());
 }
 
 /* ES5 15.10.6.3. */
 static bool
 regexp_test_impl(JSContext *cx, CallArgs args)
 {
+#ifdef JS_YARR
     MatchPair match;
     MatchConduit conduit(&match);
+#else
+    ScopedMatchPairs matches(&cx->tempLifoAlloc());
+    MatchConduit conduit(&matches);
+#endif
     RegExpRunStatus status = ExecuteRegExp(cx, args, conduit);
     args.rval().setBoolean(status == RegExpRunStatus_Success);
     return status != RegExpRunStatus_Error;
 }
 
 /* Separate interface for use by IonMonkey. */
 bool
 js::regexp_test_raw(JSContext *cx, HandleObject regexp, HandleString input, bool *result)
 {
+#ifdef JS_YARR
     MatchPair match;
     MatchConduit conduit(&match);
+#else
+    ScopedMatchPairs matches(&cx->tempLifoAlloc());
+    MatchConduit conduit(&matches);
+#endif
     RegExpRunStatus status = ExecuteRegExp(cx, regexp, input, conduit, UpdateRegExpStatics);
     *result = (status == RegExpRunStatus_Success);
     return status != RegExpRunStatus_Error;
 }
 
 bool
 js::regexp_test(JSContext *cx, unsigned argc, Value *vp)
 {
@@ -709,14 +734,19 @@ js::regexp_test_no_statics(JSContext *cx
     CallArgs args = CallArgsFromVp(argc, vp);
     JS_ASSERT(args.length() == 2);
     JS_ASSERT(IsRegExp(args[0]));
     JS_ASSERT(args[1].isString());
 
     RootedObject regexp(cx, &args[0].toObject());
     RootedString string(cx, args[1].toString());
 
+#ifdef JS_YARR
     MatchPair match;
     MatchConduit conduit(&match);
+#else
+    ScopedMatchPairs matches(&cx->tempLifoAlloc());
+    MatchConduit conduit(&matches);
+#endif
     RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, conduit, DontUpdateRegExpStatics);
     args.rval().setBoolean(status == RegExpRunStatus_Success);
     return status != RegExpRunStatus_Error;
 }
--- a/js/src/builtin/RegExp.h
+++ b/js/src/builtin/RegExp.h
@@ -14,16 +14,18 @@ js_InitRegExpClass(JSContext *cx, js::Ha
 
 /*
  * The following builtin natives are extern'd for pointer comparison in
  * other parts of the engine.
  */
 
 namespace js {
 
+class MatchConduit;
+
 // Whether RegExp statics should be updated with the input and results of a
 // regular expression execution.
 enum RegExpStaticsUpdate { UpdateRegExpStatics, DontUpdateRegExpStatics };
 
 RegExpRunStatus
 ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string,
               MatchConduit &matches, RegExpStaticsUpdate staticsUpdate);
 
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1972,29 +1972,26 @@ if test -z "$COMPILE_ENVIRONMENT"; then
     SKIP_LIBRARY_CHECKS=1
 fi
 
 dnl Configure JIT support
 
 case "$target" in
 i?86-*)
     ENABLE_ION=1
-    ENABLE_YARR_JIT=1
     AC_DEFINE(JS_CPU_X86)
     AC_DEFINE(JS_NUNBOX32)
     ;;
 x86_64*-*)
     ENABLE_ION=1
-    ENABLE_YARR_JIT=1
     AC_DEFINE(JS_CPU_X64)
     AC_DEFINE(JS_PUNBOX64)
     ;;
 arm*-*)
     ENABLE_ION=1
-    ENABLE_YARR_JIT=1
     AC_DEFINE(JS_CPU_ARM)
     AC_DEFINE(JS_NUNBOX32)
     ;;
 sparc*-*)
     if test ! "$HAVE_64BIT_OS" ; then
 dnl ENABLE_ION=0
     AC_DEFINE(JS_CPU_SPARC)
     AC_DEFINE(JS_NUNBOX32)
@@ -2005,34 +2002,24 @@ mips*-*)
     AC_DEFINE(JS_NUNBOX32)
     ;;
 esac
 
 MOZ_ARG_DISABLE_BOOL(ion,
 [  --disable-ion      Disable use of the IonMonkey JIT],
   ENABLE_ION= )
 
-MOZ_ARG_DISABLE_BOOL(yarr-jit,
-[  --disable-yarr-jit    Disable YARR JIT support],
-  ENABLE_YARR_JIT= )
-
 AC_SUBST(ENABLE_METHODJIT_SPEW)
 
 AC_SUBST(ENABLE_ION)
 
 if test "$ENABLE_ION"; then
     AC_DEFINE(JS_ION)
 fi
 
-AC_SUBST(ENABLE_YARR_JIT)
-
-if test "$ENABLE_YARR_JIT"; then
-    AC_DEFINE(ENABLE_YARR_JIT)
-fi
-
 if test -n "$COMPILE_ENVIRONMENT"; then
     MOZ_COMPILER_OPTS
 fi
 
 if test -z "$SKIP_COMPILER_CHECKS"; then
 dnl Checks for typedefs, structures, and compiler characteristics.
 dnl ========================================================
 AC_HEADER_STDC
@@ -2990,16 +2977,30 @@ MOZ_ARG_ENABLE_BOOL(trace-logging,
 
 AC_SUBST(ENABLE_TRACE_LOGGING)
 
 if test "$ENABLE_TRACE_LOGGING"; then
     AC_DEFINE(JS_TRACE_LOGGING)
 fi
 
 dnl ========================================================
+dnl = Enable yarr regexp engine
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(yarr,
+[  --enable-yarr   Enable yarr regexp engine],
+    ENABLE_YARR=1,
+    ENABLE_YARR= )
+
+AC_SUBST(ENABLE_YARR)
+
+if test "$ENABLE_YARR"; then
+    AC_DEFINE(JS_YARR)
+fi
+
+dnl ========================================================
 dnl = Enable any treating of compile warnings as errors
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(warnings-as-errors,
 [  --enable-warnings-as-errors
                           Enable treating of warnings as errors],
     MOZ_ENABLE_WARNINGS_AS_ERRORS=1,
     MOZ_ENABLE_WARNINGS_AS_ERRORS=)
 if test -z "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -142,16 +142,19 @@ class BumpChunk
     }
 
     static BumpChunk *new_(size_t chunkSize);
     static void delete_(BumpChunk *chunk);
 };
 
 } // namespace detail
 
+void
+CrashAtUnhandlableOOM(const char *reason);
+
 // LIFO bump allocator: used for phase-oriented and fast LIFO allocations.
 //
 // Note: |latest| is not necessary "last". We leave BumpChunks latent in the
 // chain after they've been released to avoid thrashing before a GC.
 class LifoAlloc
 {
     typedef detail::BumpChunk BumpChunk;
 
@@ -264,16 +267,24 @@ class LifoAlloc
             return nullptr;
 
         // Since we just created a large enough chunk, this can't fail.
         result = latest->tryAlloc(n);
         MOZ_ASSERT(result);
         return result;
     }
 
+    MOZ_ALWAYS_INLINE
+    void *allocInfallible(size_t n) {
+        if (void *result = alloc(n))
+            return result;
+        CrashAtUnhandlableOOM("LifoAlloc::allocInfallible");
+        return nullptr;
+    }
+
     // Ensures that enough space exists to satisfy N bytes worth of
     // allocation requests, not necessarily contiguous. Note that this does
     // not guarantee a successful single allocation of N bytes.
     MOZ_ALWAYS_INLINE
     bool ensureUnusedApproximate(size_t n) {
         size_t total = 0;
         for (BumpChunk *chunk = latest; chunk; chunk = chunk->next()) {
             total += chunk->unused();
@@ -380,16 +391,17 @@ class LifoAlloc
     // Doesn't perform construction; useful for lazily-initialized POD types.
     template <typename T>
     MOZ_ALWAYS_INLINE
     T *newPod() {
         return static_cast<T *>(alloc(sizeof(T)));
     }
 
     JS_DECLARE_NEW_METHODS(new_, alloc, MOZ_ALWAYS_INLINE)
+    JS_DECLARE_NEW_METHODS(newInfallible, allocInfallible, MOZ_ALWAYS_INLINE)
 
     // A mutable enumeration of the allocated data.
     class Enum
     {
         friend class LifoAlloc;
         friend class detail::BumpChunk;
 
         LifoAlloc *alloc_;  // The LifoAlloc being traversed.
@@ -485,37 +497,44 @@ class LifoAllocScope
 
     void releaseEarly() {
         JS_ASSERT(shouldRelease);
         lifoAlloc->release(mark);
         shouldRelease = false;
     }
 };
 
+enum Fallibility {
+    Fallible,
+    Infallible
+};
+
+template <Fallibility fb>
 class LifoAllocPolicy
 {
     LifoAlloc &alloc_;
 
   public:
     LifoAllocPolicy(LifoAlloc &alloc)
       : alloc_(alloc)
     {}
     void *malloc_(size_t bytes) {
-        return alloc_.alloc(bytes);
+        return fb == Fallible ? alloc_.alloc(bytes) : alloc_.allocInfallible(bytes);
     }
     void *calloc_(size_t bytes) {
         void *p = malloc_(bytes);
-        if (p)
-            memset(p, 0, bytes);
+        if (fb == Fallible && !p)
+            return nullptr;
+        memset(p, 0, bytes);
         return p;
     }
     void *realloc_(void *p, size_t oldBytes, size_t bytes) {
         void *n = malloc_(bytes);
-        if (!n)
-            return n;
+        if (fb == Fallible && !n)
+            return nullptr;
         memcpy(n, p, Min(oldBytes, bytes));
         return n;
     }
     void free_(void *p) {
     }
     void reportAllocOverflow() const {
     }
 };
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -6909,17 +6909,17 @@ Parser<ParseHandler>::newRegExp()
     size_t length = tokenStream.getTokenbuf().length();
     RegExpFlag flags = tokenStream.currentToken().regExpFlags();
 
     Rooted<RegExpObject*> reobj(context);
     RegExpStatics *res = context->global()->getRegExpStatics(context);
     if (!res)
         return null();
 
-    reobj = RegExpObject::create(context, res, chars, length, flags, &tokenStream);
+    reobj = RegExpObject::create(context, res, chars, length, flags, &tokenStream, alloc);
     if (!reobj)
         return null();
 
     return handler.newRegExp(reobj, pos(), *this);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -286,17 +286,17 @@ TokenStream::TokenStream(ExclusiveContex
     // The caller must ensure that a reference is held on the supplied principals
     // throughout compilation.
     JS_ASSERT_IF(originPrincipals, originPrincipals->refcount > 0);
 
     // Column numbers are computed as offsets from the current line's base, so the
     // initial line's base must be included in the buffer. linebase and userbuf
     // were adjusted above, and if we are starting tokenization part way through
     // this line then adjust the next character.
-    userbuf.setAddressOfNextRawChar(base);
+    userbuf.setAddressOfNextRawChar(base, /* allowPoisoned = */ true);
 
     // Nb: the following tables could be static, but initializing them here is
     // much easier.  Don't worry, the time to initialize them for each
     // TokenStream is trivial.  See bug 639420.
 
     // See getChar() for an explanation of maybeEOL[].
     memset(maybeEOL, 0, sizeof(maybeEOL));
     maybeEOL[unsigned('\n')] = true;
@@ -626,16 +626,27 @@ TokenStream::reportCompileErrorNumberVA(
     if (offset == NoOffset) {
         err.report.lineno = 0;
         err.report.column = 0;
     } else {
         err.report.lineno = srcCoords.lineNum(offset);
         err.report.column = srcCoords.columnIndex(offset);
     }
 
+    // If we have no location information, try to get one from the caller.
+    if (offset != NoOffset && !err.report.filename && cx->isJSContext()) {
+        NonBuiltinFrameIter iter(cx->asJSContext(),
+                                 FrameIter::ALL_CONTEXTS, FrameIter::GO_THROUGH_SAVED,
+                                 cx->compartment()->principals);
+        if (!iter.done() && iter.scriptFilename()) {
+            err.report.filename = iter.scriptFilename();
+            err.report.lineno = iter.computeLine(&err.report.column);
+        }
+    }
+
     err.argumentsType = (flags & JSREPORT_UC) ? ArgumentsAreUnicode : ArgumentsAreASCII;
 
     if (!js_ExpandErrorArguments(cx, js_GetErrorMessage, nullptr, errorNumber, &err.message,
                                  &err.report, err.argumentsType, args))
     {
         return false;
     }
 
new file mode 100644
--- /dev/null
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp
@@ -0,0 +1,1286 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99: */
+
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "irregexp/NativeRegExpMacroAssembler.h"
+
+#include "irregexp/RegExpStack.h"
+#include "jit/IonLinker.h"
+#include "vm/MatchPairs.h"
+
+using namespace js;
+using namespace js::irregexp;
+using namespace js::jit;
+
+/*
+ * This assembler uses the following register assignment convention:
+ *
+ * - current_character :
+ *     Must be loaded using LoadCurrentCharacter before using any of the
+ *     dispatch methods. Temporarily stores the index of capture start after a
+ *     matching pass for a global regexp.
+ * - current_position :
+ *     Current position in input, as negative offset from end of string.
+ *     Please notice that this is the byte offset, not the character offset!
+ * - input_end_pointer :
+ *     Points to byte after last character in the input.
+ * - backtrack_stack_pointer :
+ *     Points to tip of the heap allocated backtrack stack
+ * - StackPointer :
+ *     Points to tip of the native stack, used to access arguments, local
+ *     variables and RegExp registers.
+ *
+ * The tempN registers are free to use for computations.
+ */
+
+NativeRegExpMacroAssembler::NativeRegExpMacroAssembler(LifoAlloc *alloc, RegExpShared *shared,
+                                                       JSRuntime *rt, Mode mode, int registers_to_save)
+  : RegExpMacroAssembler(*alloc, shared, registers_to_save),
+    runtime(rt), mode_(mode)
+{
+    // Find physical registers for each compiler register.
+    GeneralRegisterSet regs(GeneralRegisterSet::All());
+
+    input_end_pointer = regs.takeAny();
+    current_character = regs.takeAny();
+    current_position = regs.takeAny();
+    backtrack_stack_pointer = regs.takeAny();
+    temp0 = regs.takeAny();
+    temp1 = regs.takeAny();
+    temp2 = regs.takeAny();
+
+    IonSpew(IonSpew_Codegen,
+            "Starting RegExp (input_end_pointer %s) (current_character %s)"
+            " (current_position %s) (backtrack_stack_pointer %s) (temp0 %s) temp1 (%s) temp2 (%s)",
+            input_end_pointer.name(),
+            current_character.name(),
+            current_position.name(),
+            backtrack_stack_pointer.name(),
+            temp0.name(),
+            temp1.name(),
+            temp2.name());
+
+    // Determine the non-volatile registers which might be modified by jitcode.
+    for (GeneralRegisterIterator iter(GeneralRegisterSet::NonVolatile()); iter.more(); iter++) {
+        Register reg = *iter;
+        if (!regs.has(reg))
+            savedNonVolatileRegisters.add(reg);
+    }
+
+#ifdef JS_CODEGEN_ARM
+    // ARM additionally requires that the link register be saved.
+    savedNonVolatileRegisters.add(Register::FromCode(Registers::lr));
+#endif
+
+    masm.jump(&entry_label_);
+    masm.bind(&start_label_);
+}
+
+#define SPEW_PREFIX IonSpew_Codegen, "!!! "
+
+// The signature of the code which this generates is:
+//
+// void execute(InputOutputData*);
+RegExpCode
+NativeRegExpMacroAssembler::GenerateCode(JSContext *cx)
+{
+    if (!cx->compartment()->ensureJitCompartmentExists(cx))
+        return RegExpCode();
+
+    IonSpew(SPEW_PREFIX "GenerateCode");
+
+    // We need an even number of registers, for stack alignment.
+    if (num_registers_ % 2 == 1)
+        num_registers_++;
+
+    Label return_temp0;
+
+    // Finalize code - write the entry point code now we know how many
+    // registers we need.
+    masm.bind(&entry_label_);
+
+    // Push non-volatile registers which might be modified by jitcode.
+    size_t pushedNonVolatileRegisters = 0;
+    for (GeneralRegisterForwardIterator iter(savedNonVolatileRegisters); iter.more(); ++iter) {
+        masm.Push(*iter);
+        pushedNonVolatileRegisters++;
+    }
+
+#ifndef JS_CODEGEN_X86
+    // The InputOutputData* is stored as an argument, save it on the stack
+    // above the frame.
+    masm.Push(IntArgReg0);
+#endif
+
+    size_t frameSize = sizeof(FrameData) + num_registers_ * sizeof(void *);
+    frameSize = JS_ROUNDUP(frameSize + masm.framePushed(), StackAlignment) - masm.framePushed();
+
+    // Actually emit code to start a new stack frame.
+    masm.reserveStack(frameSize);
+    masm.checkStackAlignment();
+
+    // Check if we have space on the stack.
+    Label stack_ok;
+    void *stack_limit = &runtime->mainThread.jitStackLimit;
+    masm.branchPtr(Assembler::Below, AbsoluteAddress(stack_limit), StackPointer, &stack_ok);
+
+    // Exit with an exception. There is not enough space on the stack
+    // for our working registers.
+    masm.mov(ImmWord(RegExpRunStatus_Error), temp0);
+    masm.jump(&return_temp0);
+
+    masm.bind(&stack_ok);
+
+#ifdef XP_WIN
+    // Ensure that we write to each stack page, in order. Skipping a page
+    // on Windows can cause segmentation faults. Assuming page size is 4k.
+    const int kPageSize = 4096;
+    for (int i = frameSize - sizeof(void *); i >= 0; i -= kPageSize)
+        masm.storePtr(temp0, Address(StackPointer, i));
+#endif // XP_WIN
+
+#ifndef JS_CODEGEN_X86
+    // The InputOutputData* is stored on the stack immediately above the frame.
+    Address inputOutputAddress(StackPointer, frameSize);
+#else
+    // The InputOutputData* is left in its original on stack location.
+    Address inputOutputAddress(StackPointer, frameSize + (pushedNonVolatileRegisters + 1) * sizeof(void *));
+#endif
+
+    masm.loadPtr(inputOutputAddress, temp0);
+
+    // Copy output registers to FrameData.
+    {
+        Register matchPairsRegister = input_end_pointer;
+        masm.loadPtr(Address(temp0, offsetof(InputOutputData, matches)), matchPairsRegister);
+        masm.loadPtr(Address(matchPairsRegister, MatchPairs::offsetOfPairs()), temp1);
+        masm.storePtr(temp1, Address(StackPointer, offsetof(FrameData, outputRegisters)));
+        masm.load32(Address(matchPairsRegister, MatchPairs::offsetOfPairCount()), temp1);
+        masm.lshiftPtr(Imm32(1), temp1);
+        masm.store32(temp1, Address(StackPointer, offsetof(FrameData, numOutputRegisters)));
+
+#ifdef DEBUG
+        // Bounds check numOutputRegisters.
+        Label enoughRegisters;
+        masm.cmpPtr(temp1, ImmWord(num_saved_registers_));
+        masm.j(Assembler::GreaterThanOrEqual, &enoughRegisters);
+        masm.assumeUnreachable("Not enough output registers for RegExp");
+        masm.bind(&enoughRegisters);
+#endif
+    }
+
+    // Load string end pointer.
+    masm.loadPtr(Address(temp0, offsetof(InputOutputData, inputEnd)), input_end_pointer);
+
+    // Load input start pointer, and copy to FrameData.
+    masm.loadPtr(Address(temp0, offsetof(InputOutputData, inputStart)), current_position);
+    masm.storePtr(current_position, Address(StackPointer, offsetof(FrameData, inputStart)));
+
+    // Load start index, and copy to FrameData.
+    masm.loadPtr(Address(temp0, offsetof(InputOutputData, startIndex)), temp1);
+    masm.storePtr(temp1, Address(StackPointer, offsetof(FrameData, startIndex)));
+
+    // Set up input position to be negative offset from string end.
+    masm.subPtr(input_end_pointer, current_position);
+
+    // Set temp0 to address of char before start of the string.
+    // (effectively string position -1).
+    masm.computeEffectiveAddress(Address(current_position, -char_size()), temp0);
+
+    // Store this value on the frame, for use when clearing
+    // position registers.
+    masm.storePtr(temp0, Address(StackPointer, offsetof(FrameData, inputStartMinusOne)));
+
+    // Update current position based on start index.
+    masm.computeEffectiveAddress(BaseIndex(current_position, temp1, factor()), current_position);
+
+    Label load_char_start_regexp, start_regexp;
+
+    // Load newline if index is at start, previous character otherwise.
+    masm.cmpPtr(Address(StackPointer, offsetof(FrameData, startIndex)), ImmWord(0));
+    masm.j(Assembler::NotEqual, &load_char_start_regexp);
+    masm.mov(ImmWord('\n'), current_character);
+    masm.jump(&start_regexp);
+
+    // Global regexp restarts matching here.
+    masm.bind(&load_char_start_regexp);
+
+    // Load previous char as initial value of current character register.
+    LoadCurrentCharacterUnchecked(-1, 1);
+    masm.bind(&start_regexp);
+
+    // Initialize on-stack registers.
+    JS_ASSERT(num_saved_registers_ > 0);
+
+    // Fill saved registers with initial value = start offset - 1
+    // Fill in stack push order, to avoid accessing across an unwritten
+    // page (a problem on Windows).
+    if (num_saved_registers_ > 8) {
+        masm.mov(ImmWord(register_offset(0)), temp1);
+        Label init_loop;
+        masm.bind(&init_loop);
+        masm.storePtr(temp0, BaseIndex(StackPointer, temp1, TimesOne));
+        masm.addPtr(ImmWord(sizeof(void *)), temp1);
+        masm.cmpPtr(temp1, ImmWord(register_offset(num_saved_registers_)));
+        masm.j(Assembler::LessThan, &init_loop);
+    } else {
+        // Unroll the loop.
+        for (int i = 0; i < num_saved_registers_; i++)
+            masm.storePtr(temp0, register_location(i));
+    }
+
+    // Initialize backtrack stack pointer.
+    masm.loadPtr(AbsoluteAddress(runtime->mainThread.regexpStack.addressOfBase()), backtrack_stack_pointer);
+    masm.storePtr(backtrack_stack_pointer, Address(StackPointer, offsetof(FrameData, backtrackStackBase)));
+
+    masm.jump(&start_label_);
+
+    // Exit code:
+    if (success_label_.used()) {
+        JS_ASSERT(num_saved_registers_ > 0);
+
+        Address outputRegistersAddress(StackPointer, offsetof(FrameData, outputRegisters));
+
+        // Save captures when successful.
+        masm.bind(&success_label_);
+
+        {
+            Register outputRegisters = temp1;
+            Register inputByteLength = backtrack_stack_pointer;
+
+            masm.loadPtr(outputRegistersAddress, outputRegisters);
+
+            masm.loadPtr(inputOutputAddress, temp0);
+            masm.loadPtr(Address(temp0, offsetof(InputOutputData, inputEnd)), inputByteLength);
+            masm.subPtr(Address(temp0, offsetof(InputOutputData, inputStart)), inputByteLength);
+
+            // Copy captures to output. Note that registers on the C stack are pointer width
+            // so that they might hold pointers, but output registers are int32_t.
+            for (int i = 0; i < num_saved_registers_; i++) {
+                masm.loadPtr(register_location(i), temp0);
+                if (i == 0 && global_with_zero_length_check()) {
+                    // Keep capture start in current_character for the zero-length check later.
+                    masm.mov(temp0, current_character);
+                }
+
+                // Convert to index from start of string, not end.
+                masm.addPtr(inputByteLength, temp0);
+
+                // Convert byte index to character index.
+                if (mode_ == JSCHAR)
+                    masm.rshiftPtrArithmetic(Imm32(1), temp0);
+
+                masm.store32(temp0, Address(outputRegisters, i * sizeof(int32_t)));
+            }
+        }
+
+        // Restart matching if the regular expression is flagged as global.
+        if (global()) {
+            // Increment success counter.
+            masm.add32(Imm32(1), Address(StackPointer, offsetof(FrameData, successfulCaptures)));
+
+            Address numOutputRegistersAddress(StackPointer, offsetof(FrameData, numOutputRegisters));
+
+            // Capture results have been stored, so the number of remaining global
+            // output registers is reduced by the number of stored captures.
+            masm.load32(numOutputRegistersAddress, temp0);
+
+            masm.sub32(Imm32(num_saved_registers_), temp0);
+
+            // Check whether we have enough room for another set of capture results.
+            masm.branch32(Assembler::LessThan, temp0, Imm32(num_saved_registers_), &exit_label_);
+
+            masm.store32(temp0, numOutputRegistersAddress);
+
+            // Advance the location for output.
+            masm.add32(Imm32(num_saved_registers_ * sizeof(void *)), outputRegistersAddress);
+
+            // Prepare temp0 to initialize registers with its value in the next run.
+            masm.loadPtr(Address(StackPointer, offsetof(FrameData, inputStartMinusOne)), temp0);
+
+            if (global_with_zero_length_check()) {
+                // Special case for zero-length matches.
+
+                // The capture start index was loaded into current_character above.
+                masm.branchPtr(Assembler::NotEqual, current_position, current_character,
+                               &load_char_start_regexp);
+
+                // edi (offset from the end) is zero if we already reached the end.
+                masm.testPtr(current_position, current_position);
+                masm.j(Assembler::Zero, &exit_label_);
+
+                // Advance current position after a zero-length match.
+                masm.addPtr(Imm32(char_size()), current_position);
+            }
+
+            masm.jump(&load_char_start_regexp);
+        } else {
+            masm.mov(ImmWord(RegExpRunStatus_Success), temp0);
+        }
+    }
+
+    masm.bind(&exit_label_);
+
+    if (global()) {
+        // Return the number of successful captures.
+        masm.load32(Address(StackPointer, offsetof(FrameData, successfulCaptures)), temp0);
+    }
+
+    masm.bind(&return_temp0);
+
+    // Store the result to the input structure.
+    masm.loadPtr(inputOutputAddress, temp1);
+    masm.storePtr(temp0, Address(temp1, offsetof(InputOutputData, result)));
+
+#ifndef JS_CODEGEN_X86
+    // Include the InputOutputData* when adjusting the stack size.
+    masm.freeStack(frameSize + sizeof(void *));
+#else
+    masm.freeStack(frameSize);
+#endif
+
+    // Restore non-volatile registers which were saved on entry.
+    for (GeneralRegisterBackwardIterator iter(savedNonVolatileRegisters); iter.more(); ++iter)
+        masm.Pop(*iter);
+
+    masm.abiret();
+
+    // Backtrack code (branch target for conditional backtracks).
+    if (backtrack_label_.used()) {
+        masm.bind(&backtrack_label_);
+        Backtrack();
+    }
+
+    // Backtrack stack overflow code.
+    if (stack_overflow_label_.used()) {
+        // Reached if the backtrack-stack limit has been hit. temp2 holds the
+        // StackPointer to use for accessing FrameData.
+        masm.bind(&stack_overflow_label_);
+
+        Label grow_failed;
+
+        masm.mov(ImmPtr(runtime), temp1);
+
+        // Save registers before calling C function
+        RegisterSet volatileRegs = RegisterSet::Volatile();
+#ifdef JS_CODEGEN_ARM
+        volatileRegs.add(Register::FromCode(Registers::lr));
+#endif
+        volatileRegs.takeUnchecked(temp0);
+        volatileRegs.takeUnchecked(temp1);
+        masm.PushRegsInMask(volatileRegs);
+
+        masm.setupUnalignedABICall(1, temp0);
+        masm.passABIArg(temp1);
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, GrowBacktrackStack));
+        masm.storeCallResult(temp0);
+
+        masm.PopRegsInMask(volatileRegs);
+
+        // If return false, we have failed to grow the stack, and
+        // must exit with a stack-overflow exception. Do this in the caller
+        // so that the stack is adjusted by our return instruction.
+        Label return_from_overflow_handler;
+        masm.branchTest32(Assembler::Zero, temp0, temp0, &return_from_overflow_handler);
+
+        // Otherwise, store the new backtrack stack base and recompute the new
+        // top of the stack.
+        Address backtrackStackBaseAddress(temp2, offsetof(FrameData, backtrackStackBase));
+        masm.subPtr(backtrackStackBaseAddress, backtrack_stack_pointer);
+
+        masm.loadPtr(AbsoluteAddress(runtime->mainThread.regexpStack.addressOfBase()), temp1);
+        masm.storePtr(temp1, backtrackStackBaseAddress);
+        masm.addPtr(temp1, backtrack_stack_pointer);
+
+        // Resume execution in calling code.
+        masm.bind(&return_from_overflow_handler);
+        masm.abiret();
+    }
+
+    if (exit_with_exception_label_.used()) {
+        // If any of the code above needed to exit with an exception.
+        masm.bind(&exit_with_exception_label_);
+
+        // Exit with an error result to signal thrown exception.
+        masm.mov(ImmWord(RegExpRunStatus_Error), temp0);
+        masm.jump(&return_temp0);
+    }
+
+    Linker linker(masm);
+    JitCode *code = linker.newCode<NoGC>(cx, JSC::REGEXP_CODE);
+    if (!code)
+        return RegExpCode();
+
+    for (size_t i = 0; i < labelPatches.length(); i++) {
+        const LabelPatch &v = labelPatches[i];
+        JS_ASSERT(!v.label);
+        Assembler::patchDataWithValueCheck(CodeLocationLabel(code, v.patchOffset),
+                                           ImmPtr(code->raw() + v.labelOffset),
+                                           ImmPtr(0));
+    }
+
+    IonSpew(IonSpew_Codegen, "Created RegExp (raw %p length %d)",
+            (void *) code->raw(), (int) masm.bytesNeeded());
+
+    RegExpCode res;
+    res.jitCode = code;
+    return res;
+}
+
+int
+NativeRegExpMacroAssembler::stack_limit_slack()
+{
+    return RegExpStack::kStackLimitSlack;
+}
+
+void
+NativeRegExpMacroAssembler::AdvanceCurrentPosition(int by)
+{
+    IonSpew(SPEW_PREFIX "AdvanceCurrentPosition(%d)", by);
+
+    if (by != 0)
+        masm.addPtr(Imm32(by * char_size()), current_position);
+}
+
+void
+NativeRegExpMacroAssembler::AdvanceRegister(int reg, int by)
+{
+    IonSpew(SPEW_PREFIX "AdvanceRegister(%d, %d)", reg, by);
+
+    JS_ASSERT(reg >= 0);
+    JS_ASSERT(reg < num_registers_);
+    if (by != 0)
+        masm.addPtr(Imm32(by), register_location(reg));
+}
+
+void
+NativeRegExpMacroAssembler::Backtrack()
+{
+    IonSpew(SPEW_PREFIX "Backtrack");
+
+    // Pop code location from backtrack stack and jump to location.
+    PopBacktrack(temp0);
+    masm.jump(temp0);
+}
+
+void
+NativeRegExpMacroAssembler::Bind(Label *label)
+{
+    IonSpew(SPEW_PREFIX "Bind");
+
+    masm.bind(label);
+}
+
+void
+NativeRegExpMacroAssembler::CheckAtStart(Label* on_at_start)
+{
+    IonSpew(SPEW_PREFIX "CheckAtStart");
+
+    Label not_at_start;
+
+    // Did we start the match at the start of the string at all?
+    masm.cmpPtr(Address(StackPointer, offsetof(FrameData, startIndex)), ImmWord(0));
+    BranchOrBacktrack(Assembler::NotEqual, &not_at_start);
+
+    // If we did, are we still at the start of the input?
+    masm.computeEffectiveAddress(BaseIndex(input_end_pointer, current_position, TimesOne), temp0);
+    masm.cmpPtr(Address(StackPointer, offsetof(FrameData, inputStart)), temp0);
+
+    BranchOrBacktrack(Assembler::Equal, on_at_start);
+    masm.bind(&not_at_start);
+}
+
+void
+NativeRegExpMacroAssembler::CheckNotAtStart(Label* on_not_at_start)
+{
+    IonSpew(SPEW_PREFIX "CheckNotAtStart");
+
+    // Did we start the match at the start of the string at all?
+    masm.cmpPtr(Address(StackPointer, offsetof(FrameData, startIndex)), ImmWord(0));
+    BranchOrBacktrack(Assembler::NotEqual, on_not_at_start);
+
+    // If we did, are we still at the start of the input?
+    masm.computeEffectiveAddress(BaseIndex(input_end_pointer, current_position, TimesOne), temp0);
+    masm.cmpPtr(Address(StackPointer, offsetof(FrameData, inputStart)), temp0);
+    BranchOrBacktrack(Assembler::NotEqual, on_not_at_start);
+}
+
+void
+NativeRegExpMacroAssembler::CheckCharacter(unsigned c, Label* on_equal)
+{
+    IonSpew(SPEW_PREFIX "CheckCharacter(%d)", (int) c);
+
+    masm.cmp32(current_character, Imm32(c));
+    BranchOrBacktrack(Assembler::Equal, on_equal);
+}
+
+void
+NativeRegExpMacroAssembler::CheckNotCharacter(unsigned c, Label* on_not_equal)
+{
+    IonSpew(SPEW_PREFIX "CheckNotCharacter(%d)", (int) c);
+
+    masm.cmp32(current_character, Imm32(c));
+    BranchOrBacktrack(Assembler::NotEqual, on_not_equal);
+}
+
+void
+NativeRegExpMacroAssembler::CheckCharacterAfterAnd(unsigned c, unsigned and_with,
+                                                   Label *on_equal)
+{
+    IonSpew(SPEW_PREFIX "CheckCharacterAfterAnd(%d, %d)", (int) c, (int) and_with);
+
+    if (c == 0) {
+        masm.test32(current_character, Imm32(and_with));
+        BranchOrBacktrack(Assembler::Zero, on_equal);
+    } else {
+        masm.mov(ImmWord(and_with), temp0);
+        masm.and32(current_character, temp0);
+        masm.cmp32(temp0, Imm32(c));
+        BranchOrBacktrack(Assembler::Equal, on_equal);
+    }
+}
+
+void
+NativeRegExpMacroAssembler::CheckNotCharacterAfterAnd(unsigned c, unsigned and_with,
+                                                      Label *on_not_equal)
+{
+    IonSpew(SPEW_PREFIX "CheckNotCharacterAfterAnd(%d, %d)", (int) c, (int) and_with);
+
+    if (c == 0) {
+        masm.test32(current_character, Imm32(and_with));
+        BranchOrBacktrack(Assembler::NonZero, on_not_equal);
+    } else {
+        masm.mov(ImmWord(and_with), temp0);
+        masm.and32(current_character, temp0);
+        masm.cmp32(temp0, Imm32(c));
+        BranchOrBacktrack(Assembler::NotEqual, on_not_equal);
+    }
+}
+
+void
+NativeRegExpMacroAssembler::CheckCharacterGT(jschar c, Label* on_greater)
+{
+    IonSpew(SPEW_PREFIX "CheckCharacterGT(%d)", (int) c);
+
+    masm.cmp32(current_character, Imm32(c));
+    BranchOrBacktrack(Assembler::GreaterThan, on_greater);
+}
+
+void
+NativeRegExpMacroAssembler::CheckCharacterLT(jschar c, Label* on_less)
+{
+    IonSpew(SPEW_PREFIX "CheckCharacterLT(%d)", (int) c);
+
+    masm.cmp32(current_character, Imm32(c));
+    BranchOrBacktrack(Assembler::LessThan, on_less);
+}
+
+void
+NativeRegExpMacroAssembler::CheckGreedyLoop(Label* on_tos_equals_current_position)
+{
+    IonSpew(SPEW_PREFIX "CheckGreedyLoop");
+
+    Label fallthrough;
+    masm.cmpPtr(Address(backtrack_stack_pointer, -int(sizeof(void *))), current_position);
+    masm.j(Assembler::NotEqual, &fallthrough);
+    masm.subPtr(Imm32(sizeof(void *)), backtrack_stack_pointer);  // Pop.
+    JumpOrBacktrack(on_tos_equals_current_position);
+    masm.bind(&fallthrough);
+}
+
+void
+NativeRegExpMacroAssembler::CheckNotBackReference(int start_reg, Label* on_no_match)
+{
+    IonSpew(SPEW_PREFIX "CheckNotBackReference(%d)", start_reg);
+
+    Label fallthrough;
+    Label success;
+    Label fail;
+
+    // Find length of back-referenced capture.
+    masm.loadPtr(register_location(start_reg), current_character);
+    masm.loadPtr(register_location(start_reg + 1), temp0);
+    masm.subPtr(current_character, temp0);  // Length to check.
+    masm.cmpPtr(temp0, ImmWord(0));
+
+    // Fail on partial or illegal capture (start of capture after end of capture).
+    BranchOrBacktrack(Assembler::LessThan, on_no_match);
+
+    // Succeed on empty capture (including no capture).
+    masm.j(Assembler::Equal, &fallthrough);
+
+    // Check that there are sufficient characters left in the input.
+    masm.mov(current_position, temp1);
+    masm.addPtr(temp0, temp1);
+    masm.cmpPtr(temp1, ImmWord(0));
+    BranchOrBacktrack(Assembler::GreaterThan, on_no_match);
+
+    // Save register to make it available below.
+    masm.push(backtrack_stack_pointer);
+
+    // Compute pointers to match string and capture string
+    masm.computeEffectiveAddress(BaseIndex(input_end_pointer, current_position, TimesOne), temp1); // Start of match.
+    masm.addPtr(input_end_pointer, current_character); // Start of capture.
+    masm.computeEffectiveAddress(BaseIndex(temp0, temp1, TimesOne), backtrack_stack_pointer); // End of match.
+
+    Label loop;
+    masm.bind(&loop);
+    if (mode_ == ASCII) {
+        MOZ_ASSUME_UNREACHABLE("Ascii loading not implemented");
+    } else {
+        JS_ASSERT(mode_ == JSCHAR);
+        masm.load16ZeroExtend(Address(current_character, 0), temp0);
+        masm.load16ZeroExtend(Address(temp1, 0), temp2);
+    }
+    masm.branch32(Assembler::NotEqual, temp0, temp2, &fail);
+
+    // Increment pointers into capture and match string.
+    masm.addPtr(Imm32(char_size()), current_character);
+    masm.addPtr(Imm32(char_size()), temp1);
+
+    // Check if we have reached end of match area.
+    masm.branchPtr(Assembler::Below, temp1, backtrack_stack_pointer, &loop);
+    masm.jump(&success);
+
+    masm.bind(&fail);
+
+    // Restore backtrack stack pointer.
+    masm.pop(backtrack_stack_pointer);
+    JumpOrBacktrack(on_no_match);
+
+    masm.bind(&success);
+
+    // Move current character position to position after match.
+    masm.mov(backtrack_stack_pointer, current_position);
+    masm.subPtr(input_end_pointer, current_position);
+
+    // Restore backtrack stack pointer.
+    masm.pop(backtrack_stack_pointer);
+
+    masm.bind(&fallthrough);
+}
+
+void
+NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, Label* on_no_match)
+{
+    IonSpew(SPEW_PREFIX "CheckNotBackReferenceIgnoreCase(%d)", start_reg);
+
+    Label fallthrough;
+
+    masm.loadPtr(register_location(start_reg), current_character);  // Index of start of capture
+    masm.loadPtr(register_location(start_reg + 1), temp1);  // Index of end of capture
+    masm.subPtr(current_character, temp1);  // Length of capture.
+    masm.cmpPtr(temp1, ImmWord(0));
+
+    // The length of a capture should not be negative. This can only happen
+    // if the end of the capture is unrecorded, or at a point earlier than
+    // the start of the capture.
+    BranchOrBacktrack(Assembler::LessThan, on_no_match);
+
+    // If length is zero, either the capture is empty or it is completely
+    // uncaptured. In either case succeed immediately.
+    masm.j(Assembler::Equal, &fallthrough);
+
+    // Check that there are sufficient characters left in the input.
+    masm.mov(current_position, temp0);
+    masm.addPtr(temp1, temp0);
+    masm.cmpPtr(temp0, ImmWord(0));
+    BranchOrBacktrack(Assembler::GreaterThan, on_no_match);
+
+    if (mode_ == ASCII) {
+        MOZ_ASSUME_UNREACHABLE("Ascii case not implemented");
+    } else {
+        JS_ASSERT(mode_ == JSCHAR);
+
+        // Note: temp1 needs to be saved/restored if it is volatile, as it is used after the call.
+        RegisterSet volatileRegs = RegisterSet::Volatile();
+        volatileRegs.takeUnchecked(temp0);
+        volatileRegs.takeUnchecked(temp2);
+        masm.PushRegsInMask(volatileRegs);
+
+        // Set byte_offset1.
+        // Start of capture, where current_character already holds string-end negative offset.
+        masm.addPtr(input_end_pointer, current_character);
+
+        // Set byte_offset2.
+        // Found by adding negative string-end offset of current position
+        // to end of string.
+        masm.addPtr(input_end_pointer, current_position);
+
+        // Parameters are
+        //   Address byte_offset1 - Address captured substring's start.
+        //   Address byte_offset2 - Address of current character position.
+        //   size_t byte_length - length of capture in bytes(!)
+        masm.setupUnalignedABICall(3, temp0);
+        masm.passABIArg(current_character);
+        masm.passABIArg(current_position);
+        masm.passABIArg(temp1);
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, CaseInsensitiveCompareStrings));
+        masm.storeCallResult(temp0);
+
+        masm.PopRegsInMask(volatileRegs);
+
+        // Check if function returned non-zero for success or zero for failure.
+        masm.test32(temp0, temp0);
+        BranchOrBacktrack(Assembler::Zero, on_no_match);
+
+        // On success, increment position by length of capture.
+        masm.addPtr(temp1, current_position);
+    }
+
+    masm.bind(&fallthrough);
+}
+
+void
+NativeRegExpMacroAssembler::CheckNotCharacterAfterMinusAnd(jschar c, jschar minus, jschar and_with,
+                                                           Label* on_not_equal)
+{
+    IonSpew(SPEW_PREFIX "CheckNotCharacterAfterMinusAnd(%d, %d, %d)", (int) c, (int) minus, (int) and_with);
+
+    masm.computeEffectiveAddress(Address(current_character, -minus), temp0);
+    if (c == 0) {
+        masm.test32(temp0, Imm32(and_with));
+        BranchOrBacktrack(Assembler::NonZero, on_not_equal);
+    } else {
+        masm.and32(Imm32(and_with), temp0);
+        masm.cmp32(temp0, Imm32(c));
+        BranchOrBacktrack(Assembler::NotEqual, on_not_equal);
+    }
+}
+
+void
+NativeRegExpMacroAssembler::CheckCharacterInRange(jschar from, jschar to,
+                                                  Label* on_in_range)
+{
+    IonSpew(SPEW_PREFIX "CheckCharacterInRange(%d, %d)", (int) from, (int) to);
+
+    masm.computeEffectiveAddress(Address(current_character, -from), temp0);
+    masm.cmp32(temp0, Imm32(to - from));
+    BranchOrBacktrack(Assembler::BelowOrEqual, on_in_range);
+}
+
+void
+NativeRegExpMacroAssembler::CheckCharacterNotInRange(jschar from, jschar to,
+                                                     Label* on_not_in_range)
+{
+    IonSpew(SPEW_PREFIX "CheckCharacterNotInRange(%d, %d)", (int) from, (int) to);
+
+    masm.computeEffectiveAddress(Address(current_character, -from), temp0);
+    masm.cmp32(temp0, Imm32(to - from));
+    BranchOrBacktrack(Assembler::Above, on_not_in_range);
+}
+
+void
+NativeRegExpMacroAssembler::CheckBitInTable(uint8_t *table, Label *on_bit_set)
+{
+    IonSpew(SPEW_PREFIX "CheckBitInTable");
+
+    JS_ASSERT(mode_ != ASCII); // Ascii case not handled here.
+
+    masm.mov(ImmPtr(table), temp0);
+    masm.mov(ImmWord(kTableSize - 1), temp1);
+    masm.and32(current_character, temp1);
+
+    masm.load8ZeroExtend(BaseIndex(temp0, temp1, TimesOne), temp0);
+    masm.test32(temp0, temp0);
+    BranchOrBacktrack(Assembler::NotEqual, on_bit_set);
+}
+
+void
+NativeRegExpMacroAssembler::Fail()
+{
+    IonSpew(SPEW_PREFIX "Fail");
+
+    if (!global())
+        masm.mov(ImmWord(RegExpRunStatus_Success_NotFound), temp0);
+    masm.jump(&exit_label_);
+}
+
+void
+NativeRegExpMacroAssembler::IfRegisterGE(int reg, int comparand, Label* if_ge)
+{
+    IonSpew(SPEW_PREFIX "IfRegisterGE(%d, %d)", reg, comparand);
+
+    masm.cmpPtr(register_location(reg), ImmWord(comparand));
+    BranchOrBacktrack(Assembler::GreaterThanOrEqual, if_ge);
+}
+
+void
+NativeRegExpMacroAssembler::IfRegisterLT(int reg, int comparand, Label* if_lt)
+{
+    IonSpew(SPEW_PREFIX "IfRegisterLT(%d, %d)", reg, comparand);
+
+    masm.cmpPtr(register_location(reg), ImmWord(comparand));
+    BranchOrBacktrack(Assembler::LessThan, if_lt);
+}
+
+void
+NativeRegExpMacroAssembler::IfRegisterEqPos(int reg, Label* if_eq)
+{
+    IonSpew(SPEW_PREFIX "IfRegisterEqPos(%d)", reg);
+
+    masm.cmpPtr(register_location(reg), current_position);
+    BranchOrBacktrack(Assembler::Equal, if_eq);
+}
+
+void
+NativeRegExpMacroAssembler::LoadCurrentCharacter(int cp_offset, Label* on_end_of_input,
+                                                 bool check_bounds, int characters)
+{
+    IonSpew(SPEW_PREFIX "LoadCurrentCharacter(%d, %d)", cp_offset, characters);
+
+    JS_ASSERT(cp_offset >= -1);      // ^ and \b can look behind one character.
+    JS_ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
+    if (check_bounds)
+        CheckPosition(cp_offset + characters - 1, on_end_of_input);
+    LoadCurrentCharacterUnchecked(cp_offset, characters);
+}
+
+void
+NativeRegExpMacroAssembler::LoadCurrentCharacterUnchecked(int cp_offset, int characters)
+{
+    IonSpew(SPEW_PREFIX "LoadCurrentCharacterUnchecked(%d, %d)", cp_offset, characters);
+
+    JS_ASSERT(characters == 1);
+    if (mode_ == ASCII) {
+        MOZ_ASSUME_UNREACHABLE("Ascii loading not implemented");
+    } else {
+        JS_ASSERT(mode_ == JSCHAR);
+        masm.load16ZeroExtend(BaseIndex(input_end_pointer, current_position, TimesOne, cp_offset * sizeof(jschar)),
+                              current_character);
+    }
+}
+
+void
+NativeRegExpMacroAssembler::PopCurrentPosition()
+{
+    IonSpew(SPEW_PREFIX "PopCurrentPosition");
+
+    PopBacktrack(current_position);
+}
+
+void
+NativeRegExpMacroAssembler::PopRegister(int register_index)
+{
+    IonSpew(SPEW_PREFIX "PopRegister(%d)", register_index);
+
+    PopBacktrack(temp0);
+    masm.storePtr(temp0, register_location(register_index));
+}
+
+void
+NativeRegExpMacroAssembler::PushBacktrack(Label *label)
+{
+    IonSpew(SPEW_PREFIX "PushBacktrack");
+
+    CodeOffsetLabel patchOffset = masm.movWithPatch(ImmPtr(nullptr), temp0);
+
+    JS_ASSERT(!label->bound());
+    if (!labelPatches.append(LabelPatch(label, patchOffset)))
+        CrashAtUnhandlableOOM("NativeRegExpMacroAssembler::PushBacktrack");
+
+    PushBacktrack(temp0);
+    CheckBacktrackStackLimit();
+}
+
+void
+NativeRegExpMacroAssembler::BindBacktrack(Label *label)
+{
+    IonSpew(SPEW_PREFIX "BindBacktrack");
+
+    Bind(label);
+
+    for (size_t i = 0; i < labelPatches.length(); i++) {
+        LabelPatch &v = labelPatches[i];
+        if (v.label == label) {
+            v.labelOffset = label->offset();
+            v.label = nullptr;
+            break;
+        }
+    }
+}
+
+void
+NativeRegExpMacroAssembler::PushBacktrack(Register source)
+{
+    IonSpew(SPEW_PREFIX "PushBacktrack");
+
+    JS_ASSERT(source != backtrack_stack_pointer);
+
+    // Notice: This updates flags, unlike normal Push.
+    masm.storePtr(source, Address(backtrack_stack_pointer, 0));
+    masm.addPtr(Imm32(sizeof(void *)), backtrack_stack_pointer);
+}
+
+void
+NativeRegExpMacroAssembler::PushBacktrack(int32_t value)
+{
+    IonSpew(SPEW_PREFIX "PushBacktrack(%d)", (int) value);
+
+    // Notice: This updates flags, unlike normal Push.
+    masm.storePtr(ImmWord(value), Address(backtrack_stack_pointer, 0));
+    masm.addPtr(Imm32(sizeof(void *)), backtrack_stack_pointer);
+}
+
+void
+NativeRegExpMacroAssembler::PopBacktrack(Register target)
+{
+    IonSpew(SPEW_PREFIX "PopBacktrack");
+
+    JS_ASSERT(target != backtrack_stack_pointer);
+
+    // Notice: This updates flags, unlike normal Pop.
+    masm.subPtr(Imm32(sizeof(void *)), backtrack_stack_pointer);
+    masm.loadPtr(Address(backtrack_stack_pointer, 0), target);
+}
+
+void
+NativeRegExpMacroAssembler::CheckBacktrackStackLimit()
+{
+    IonSpew(SPEW_PREFIX "CheckBacktrackStackLimit");
+
+    const void *limitAddr = runtime->mainThread.regexpStack.addressOfLimit();
+
+    Label no_stack_overflow;
+    masm.branchPtr(Assembler::AboveOrEqual, AbsoluteAddress(limitAddr),
+                   backtrack_stack_pointer, &no_stack_overflow);
+
+    // Copy the stack pointer before the call() instruction modifies it.
+    masm.mov(StackPointer, temp2);
+
+    masm.call(&stack_overflow_label_);
+    masm.bind(&no_stack_overflow);
+
+    // Exit with an exception if the call failed.
+    masm.test32(temp0, temp0);
+    masm.j(Assembler::Zero, &exit_with_exception_label_);
+}
+
+void
+NativeRegExpMacroAssembler::PushCurrentPosition()
+{
+    IonSpew(SPEW_PREFIX "PushCurrentPosition");
+
+    PushBacktrack(current_position);
+}
+
+void
+NativeRegExpMacroAssembler::PushRegister(int register_index, StackCheckFlag check_stack_limit)
+{
+    IonSpew(SPEW_PREFIX "PushRegister(%d)", register_index);
+
+    masm.loadPtr(register_location(register_index), temp0);
+    PushBacktrack(temp0);
+    if (check_stack_limit)
+        CheckBacktrackStackLimit();
+}
+
+void
+NativeRegExpMacroAssembler::ReadCurrentPositionFromRegister(int reg)
+{
+    IonSpew(SPEW_PREFIX "ReadCurrentPositionFromRegister(%d)", reg);
+
+    masm.loadPtr(register_location(reg), current_position);
+}
+
+void
+NativeRegExpMacroAssembler::WriteCurrentPositionToRegister(int reg, int cp_offset)
+{
+    IonSpew(SPEW_PREFIX "WriteCurrentPositionToRegister(%d, %d)", reg, cp_offset);
+
+    if (cp_offset == 0) {
+        masm.storePtr(current_position, register_location(reg));
+    } else {
+        masm.computeEffectiveAddress(Address(current_position, cp_offset * char_size()), temp0);
+        masm.storePtr(temp0, register_location(reg));
+    }
+}
+
+void
+NativeRegExpMacroAssembler::ReadBacktrackStackPointerFromRegister(int reg)
+{
+    IonSpew(SPEW_PREFIX "ReadBacktrackStackPointerFromRegister(%d)", reg);
+
+    masm.loadPtr(register_location(reg), backtrack_stack_pointer);
+    masm.addPtr(Address(StackPointer, offsetof(FrameData, backtrackStackBase)), backtrack_stack_pointer);
+}
+
+void
+NativeRegExpMacroAssembler::WriteBacktrackStackPointerToRegister(int reg)
+{
+    IonSpew(SPEW_PREFIX "WriteBacktrackStackPointerToRegister(%d)", reg);
+
+    masm.mov(backtrack_stack_pointer, temp0);
+    masm.subPtr(Address(StackPointer, offsetof(FrameData, backtrackStackBase)), temp0);
+    masm.storePtr(temp0, register_location(reg));
+}
+
+void
+NativeRegExpMacroAssembler::SetCurrentPositionFromEnd(int by)
+{
+    IonSpew(SPEW_PREFIX "SetCurrentPositionFromEnd(%d)", by);
+
+    Label after_position;
+    masm.cmpPtr(current_position, ImmWord(-by * char_size()));
+    masm.j(Assembler::GreaterThanOrEqual, &after_position);
+    masm.mov(ImmWord(-by * char_size()), current_position);
+
+    // On RegExp code entry (where this operation is used), the character before
+    // the current position is expected to be already loaded.
+    // We have advanced the position, so it's safe to read backwards.
+    LoadCurrentCharacterUnchecked(-1, 1);
+    masm.bind(&after_position);
+}
+
+void
+NativeRegExpMacroAssembler::SetRegister(int register_index, int to)
+{
+    IonSpew(SPEW_PREFIX "SetRegister(%d, %d)", register_index, to);
+
+    JS_ASSERT(register_index >= num_saved_registers_);  // Reserved for positions!
+    masm.storePtr(ImmWord(to), register_location(register_index));
+}
+
+bool
+NativeRegExpMacroAssembler::Succeed()
+{
+    IonSpew(SPEW_PREFIX "Succeed");
+
+    masm.jump(&success_label_);
+    return global();
+}
+
+void
+NativeRegExpMacroAssembler::ClearRegisters(int reg_from, int reg_to)
+{
+    IonSpew(SPEW_PREFIX "ClearRegisters(%d, %d)", reg_from, reg_to);
+
+    JS_ASSERT(reg_from <= reg_to);
+    masm.loadPtr(Address(StackPointer, offsetof(FrameData, inputStartMinusOne)), temp0);
+    for (int reg = reg_from; reg <= reg_to; reg++)
+        masm.storePtr(temp0, register_location(reg));
+}
+
+void
+NativeRegExpMacroAssembler::CheckPosition(int cp_offset, Label* on_outside_input)
+{
+    IonSpew(SPEW_PREFIX "CheckPosition(%d)", cp_offset);
+
+    masm.cmpPtr(current_position, ImmWord(-cp_offset * char_size()));
+    BranchOrBacktrack(Assembler::GreaterThanOrEqual, on_outside_input);
+}
+
+void
+NativeRegExpMacroAssembler::BranchOrBacktrack(Assembler::Condition condition, Label *to)
+{
+    IonSpew(SPEW_PREFIX "BranchOrBacktrack");
+
+    if (to)
+        masm.j(condition, to);
+    else
+        masm.j(condition, &backtrack_label_);
+}
+
+void
+NativeRegExpMacroAssembler::JumpOrBacktrack(Label *to)
+{
+    IonSpew(SPEW_PREFIX "JumpOrBacktrack");
+
+    if (to)
+        masm.jump(to);
+    else
+        Backtrack();
+}
+
+bool
+NativeRegExpMacroAssembler::CheckSpecialCharacterClass(jschar type, Label* on_no_match)
+{
+    IonSpew(SPEW_PREFIX "CheckSpecialCharacterClass(%d)", (int) type);
+
+    // Range checks (c in min..max) are generally implemented by an unsigned
+    // (c - min) <= (max - min) check
+    switch (type) {
+      case 's':
+        // Match space-characters
+        if (mode_ == ASCII)
+            MOZ_ASSUME_UNREACHABLE("Ascii version not implemented");
+        return false;
+      case 'S':
+        // The emitted code for generic character classes is good enough.
+        return false;
+      case 'd':
+        // Match ASCII digits ('0'..'9')
+        masm.computeEffectiveAddress(Address(current_character, -'0'), temp0);
+        masm.cmp32(temp0, Imm32('9' - '0'));
+        BranchOrBacktrack(Assembler::Above, on_no_match);
+        return true;
+      case 'D':
+        // Match non ASCII-digits
+        masm.computeEffectiveAddress(Address(current_character, -'0'), temp0);
+        masm.cmp32(temp0, Imm32('9' - '0'));
+        BranchOrBacktrack(Assembler::BelowOrEqual, on_no_match);
+        return true;
+      case '.': {
+        // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
+        masm.mov(current_character, temp0);
+        masm.xor32(Imm32(0x01), temp0);
+
+        // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
+        masm.sub32(Imm32(0x0b), temp0);
+        masm.cmp32(temp0, Imm32(0x0c - 0x0b));
+        BranchOrBacktrack(Assembler::BelowOrEqual, on_no_match);
+        if (mode_ == JSCHAR) {
+            // Compare original value to 0x2028 and 0x2029, using the already
+            // computed (current_char ^ 0x01 - 0x0b). I.e., check for
+            // 0x201d (0x2028 - 0x0b) or 0x201e.
+            masm.sub32(Imm32(0x2028 - 0x0b), temp0);
+            masm.cmp32(temp0, Imm32(0x2029 - 0x2028));
+            BranchOrBacktrack(Assembler::BelowOrEqual, on_no_match);
+        }
+        return true;
+      }
+      case 'w': {
+        if (mode_ != ASCII) {
+            // Table is 128 entries, so all ASCII characters can be tested.
+            masm.cmp32(current_character, Imm32('z'));
+            BranchOrBacktrack(Assembler::Above, on_no_match);
+        }
+        JS_ASSERT(0 == word_character_map[0]);  // Character '\0' is not a word char.
+        masm.mov(ImmPtr(word_character_map), temp0);
+        masm.load8ZeroExtend(BaseIndex(temp0, current_character, TimesOne), temp0);
+        masm.test32(temp0, temp0);
+        BranchOrBacktrack(Assembler::Zero, on_no_match);
+        return true;
+      }
+      case 'W': {
+        Label done;
+        if (mode_ != ASCII) {
+            // Table is 128 entries, so all ASCII characters can be tested.
+            masm.cmp32(current_character, Imm32('z'));
+            masm.j(Assembler::Above, &done);
+        }
+        JS_ASSERT(0 == word_character_map[0]);  // Character '\0' is not a word char.
+        masm.mov(ImmPtr(word_character_map), temp0);
+        masm.load8ZeroExtend(BaseIndex(temp0, current_character, TimesOne), temp0);
+        masm.test32(temp0, temp0);
+        BranchOrBacktrack(Assembler::NonZero, on_no_match);
+        if (mode_ != ASCII)
+            masm.bind(&done);
+        return true;
+      }
+        // Non-standard classes (with no syntactic shorthand) used internally.
+      case '*':
+        // Match any character.
+        return true;
+      case 'n': {
+        // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 or 0x2029).
+        // The opposite of '.'.
+        masm.mov(current_character, temp0);
+        masm.xor32(Imm32(0x01), temp0);
+
+        // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
+        masm.sub32(Imm32(0x0b), temp0);
+        masm.cmp32(temp0, Imm32(0x0c - 0x0b));
+
+        if (mode_ == ASCII) {
+            BranchOrBacktrack(Assembler::Above, on_no_match);
+        } else {
+            Label done;
+            BranchOrBacktrack(Assembler::BelowOrEqual, &done);
+            JS_ASSERT(JSCHAR == mode_);
+
+            // Compare original value to 0x2028 and 0x2029, using the already
+            // computed (current_char ^ 0x01 - 0x0b). I.e., check for
+            // 0x201d (0x2028 - 0x0b) or 0x201e.
+            masm.sub32(Imm32(0x2028 - 0x0b), temp0);
+            masm.cmp32(temp0, Imm32(1));
+            BranchOrBacktrack(Assembler::Above, on_no_match);
+
+            masm.bind(&done);
+        }
+        return true;
+      }
+        // No custom implementation (yet):
+      default:
+        return false;
+    }
+}
+
+bool
+NativeRegExpMacroAssembler::CanReadUnaligned()
+{
+    // XXX Bug 1006799 should this be enabled? Unaligned loads can be slow even
+    // on platforms where they are supported.
+    return false;
+}
+
+const uint8_t
+NativeRegExpMacroAssembler::word_character_map[] =
+{
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,  // '0' - '7'
+    0xffu, 0xffu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,  // '8' - '9'
+
+    0x00u, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,  // 'A' - 'G'
+    0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,  // 'H' - 'O'
+    0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,  // 'P' - 'W'
+    0xffu, 0xffu, 0xffu, 0x00u, 0x00u, 0x00u, 0x00u, 0xffu,  // 'X' - 'Z', '_'
+
+    0x00u, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,  // 'a' - 'g'
+    0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,  // 'h' - 'o'
+    0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,  // 'p' - 'w'
+    0xffu, 0xffu, 0xffu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,  // 'x' - 'z'
+
+    // Latin-1 range
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+    0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
+};
new file mode 100644
--- /dev/null
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.h
@@ -0,0 +1,224 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99: */
+
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_NATIVE_REGEXP_MACRO_ASSEMBLER_H_
+#define V8_NATIVE_REGEXP_MACRO_ASSEMBLER_H_
+
+#ifdef JS_ION
+
+#include "irregexp/RegExpMacroAssembler.h"
+
+namespace js {
+namespace irregexp {
+
+struct InputOutputData
+{
+    const jschar *inputStart;
+    const jschar *inputEnd;
+
+    // Index into inputStart (in chars) at which to begin matching.
+    size_t startIndex;
+
+    MatchPairs *matches;
+
+    // RegExpMacroAssembler::Result for non-global regexps, number of captures
+    // for global regexps.
+    int32_t result;
+
+    InputOutputData(const jschar *inputStart, const jschar *inputEnd,
+                    size_t startIndex, MatchPairs *matches)
+      : inputStart(inputStart),
+        inputEnd(inputEnd),
+        startIndex(startIndex),
+        matches(matches),
+        result(0)
+    {}
+};
+
+struct FrameData
+{
+    // Copy of the input/output data's data.
+    jschar *inputStart;
+    size_t startIndex;
+
+    // Pointer to the character before the input start.
+    jschar *inputStartMinusOne;
+
+    // Copy of the input MatchPairs registers, may be modified by JIT code.
+    int32_t *outputRegisters;
+    int32_t numOutputRegisters;
+
+    int32_t successfulCaptures;
+
+    void *backtrackStackBase;
+};
+
+class MOZ_STACK_CLASS NativeRegExpMacroAssembler : public RegExpMacroAssembler
+{
+  public:
+    // Type of input string to generate code for.
+    enum Mode { ASCII = 1, JSCHAR = 2 };
+
+    NativeRegExpMacroAssembler(LifoAlloc *alloc, RegExpShared *shared,
+                               JSRuntime *rt, Mode mode, int registers_to_save);
+
+    // Inherited virtual methods.
+    RegExpCode GenerateCode(JSContext *cx);
+    int stack_limit_slack();
+    bool CanReadUnaligned();
+    void AdvanceCurrentPosition(int by);
+    void AdvanceRegister(int reg, int by);
+    void Backtrack();
+    void Bind(jit::Label* label);
+    void CheckAtStart(jit::Label* on_at_start);
+    void CheckCharacter(unsigned c, jit::Label* on_equal);
+    void CheckCharacterAfterAnd(unsigned c, unsigned and_with, jit::Label* on_equal);
+    void CheckCharacterGT(jschar limit, jit::Label* on_greater);
+    void CheckCharacterLT(jschar limit, jit::Label* on_less);
+    void CheckGreedyLoop(jit::Label* on_tos_equals_current_position);
+    void CheckNotAtStart(jit::Label* on_not_at_start);
+    void CheckNotBackReference(int start_reg, jit::Label* on_no_match);
+    void CheckNotBackReferenceIgnoreCase(int start_reg, jit::Label* on_no_match);
+    void CheckNotCharacter(unsigned c, jit::Label* on_not_equal);
+    void CheckNotCharacterAfterAnd(unsigned c, unsigned and_with, jit::Label* on_not_equal);
+    void CheckNotCharacterAfterMinusAnd(jschar c, jschar minus, jschar and_with,
+                                        jit::Label* on_not_equal);
+    void CheckCharacterInRange(jschar from, jschar to,
+                               jit::Label* on_in_range);
+    void CheckCharacterNotInRange(jschar from, jschar to,
+                                  jit::Label* on_not_in_range);
+    void CheckBitInTable(uint8_t *table, jit::Label* on_bit_set);
+    void CheckPosition(int cp_offset, jit::Label* on_outside_input);
+    void JumpOrBacktrack(jit::Label *to);
+    bool CheckSpecialCharacterClass(jschar type, jit::Label* on_no_match);
+    void Fail();
+    void IfRegisterGE(int reg, int comparand, jit::Label* if_ge);
+    void IfRegisterLT(int reg, int comparand, jit::Label* if_lt);
+    void IfRegisterEqPos(int reg, jit::Label* if_eq);
+    void LoadCurrentCharacter(int cp_offset, jit::Label* on_end_of_input,
+                              bool check_bounds = true, int characters = 1);
+    void PopCurrentPosition();
+    void PopRegister(int register_index);
+    void PushCurrentPosition();
+    void PushRegister(int register_index, StackCheckFlag check_stack_limit);
+    void ReadCurrentPositionFromRegister(int reg);
+    void ReadBacktrackStackPointerFromRegister(int reg);
+    void SetCurrentPositionFromEnd(int by);
+    void SetRegister(int register_index, int to);
+    bool Succeed();
+    void WriteCurrentPositionToRegister(int reg, int cp_offset);
+    void ClearRegisters(int reg_from, int reg_to);
+    void WriteBacktrackStackPointerToRegister(int reg);
+    void PushBacktrack(jit::Label *label);
+    void BindBacktrack(jit::Label *label);
+
+    // Compares two-byte strings case insensitively.
+    // Called from generated RegExp code.
+    static int CaseInsensitiveCompareUC16(jit::Address byte_offset1,
+                                          jit::Address byte_offset2,
+                                          size_t byte_length);
+
+    // Byte map of one byte characters with a 0xff if the character is a word
+    // character (digit, letter or underscore) and 0x00 otherwise.
+    // Used by generated RegExp code.
+    static const uint8_t word_character_map[256];
+
+    // Byte size of chars in the string to match (decided by the Mode argument)
+    inline int char_size() { return static_cast<int>(mode_); }
+    inline jit::Scale factor() { return mode_ == JSCHAR ? jit::TimesTwo : jit::TimesOne; }
+
+    void BranchOrBacktrack(jit::Assembler::Condition condition, jit::Label *to);
+
+    // Pushes a register or constant on the backtrack stack. Decrements the
+    // stack pointer by a word size and stores the register's value there.
+    void PushBacktrack(jit::Register value);
+    void PushBacktrack(int32_t value);
+
+    // Pop a value from the backtrack stack.
+    void PopBacktrack(jit::Register target);
+
+    // Check whether we are exceeding the stack limit on the backtrack stack.
+    void CheckBacktrackStackLimit();
+
+    void LoadCurrentCharacterUnchecked(int cp_offset, int characters);
+
+  private:
+    jit::MacroAssembler masm;
+
+    JSRuntime *runtime;
+    Mode mode_;
+    jit::Label entry_label_;
+    jit::Label start_label_;
+    jit::Label backtrack_label_;
+    jit::Label success_label_;
+    jit::Label exit_label_;
+    jit::Label stack_overflow_label_;
+    jit::Label exit_with_exception_label_;
+
+    jit::GeneralRegisterSet savedNonVolatileRegisters;
+
+    struct LabelPatch {
+        // Once it is bound via BindBacktrack, |label| becomes null and
+        // |labelOffset| is set.
+        jit::Label *label;
+        size_t labelOffset;
+
+        jit::CodeOffsetLabel patchOffset;
+
+        LabelPatch(jit::Label *label, jit::CodeOffsetLabel patchOffset)
+          : label(label), labelOffset(0), patchOffset(patchOffset)
+        {}
+    };
+
+    Vector<LabelPatch, 4, SystemAllocPolicy> labelPatches;
+
+    // See RegExpMacroAssembler.cpp for the meaning of these registers.
+    jit::Register input_end_pointer;
+    jit::Register current_character;
+    jit::Register current_position;
+    jit::Register backtrack_stack_pointer;
+    jit::Register temp0, temp1, temp2;
+
+    // The frame_pointer-relative location of a regexp register.
+    jit::Address register_location(int register_index) {
+        checkRegister(register_index);
+        return jit::Address(jit::StackPointer, register_offset(register_index));
+    }
+
+    int32_t register_offset(int register_index) {
+        return sizeof(FrameData) + register_index * sizeof(void *);
+    }
+};
+
+} }  // namespace js::irregexp
+
+#endif // JS_ION
+
+#endif  // V8_NATIVE_REGEXP_MACRO_ASSEMBLER_H_
new file mode 100644
--- /dev/null
+++ b/js/src/irregexp/RegExpAST.cpp
@@ -0,0 +1,265 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99: */
+
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "irregexp/RegExpAST.h"
+
+using namespace js;
+using namespace js::irregexp;
+
+#define MAKE_ACCEPT(Name)                                            \
+  void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) {   \
+    return visitor->Visit##Name(this, data);                         \
+  }
+FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ACCEPT)
+#undef MAKE_ACCEPT
+
+#define MAKE_TYPE_CASE(Name)                                         \
+  RegExp##Name* RegExpTree::As##Name() {                             \
+    return nullptr;                                                  \
+  }                                                                  \
+  bool RegExpTree::Is##Name() { return false; }
+FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
+#undef MAKE_TYPE_CASE
+
+#define MAKE_TYPE_CASE(Name)                                        \
+  RegExp##Name* RegExp##Name::As##Name() {                          \
+    return this;                                                    \
+  }                                                                 \
+  bool RegExp##Name::Is##Name() { return true; }
+FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
+#undef MAKE_TYPE_CASE
+
+static Interval
+ListCaptureRegisters(const RegExpTreeVector &children)
+{
+    Interval result = Interval::Empty();
+    for (size_t i = 0; i < children.length(); i++)
+        result = result.Union(children[i]->CaptureRegisters());
+    return result;
+}
+
+// ----------------------------------------------------------------------------
+// RegExpDisjunction
+
+RegExpDisjunction::RegExpDisjunction(RegExpTreeVector *alternatives)
+  : alternatives_(alternatives)
+{
+    JS_ASSERT(alternatives->length() > 1);
+    RegExpTree* first_alternative = (*alternatives)[0];
+    min_match_ = first_alternative->min_match();
+    max_match_ = first_alternative->max_match();
+    for (size_t i = 1; i < alternatives->length(); i++) {
+        RegExpTree* alternative = (*alternatives)[i];
+        min_match_ = Min(min_match_, alternative->min_match());
+        max_match_ = Max(max_match_, alternative->max_match());
+    }
+}
+
+Interval
+RegExpDisjunction::CaptureRegisters()
+{
+    return ListCaptureRegisters(alternatives());
+}
+
+bool
+RegExpDisjunction::IsAnchoredAtStart()
+{
+    const RegExpTreeVector &alternatives = this->alternatives();
+    for (size_t i = 0; i < alternatives.length(); i++) {
+        if (!alternatives[i]->IsAnchoredAtStart())
+            return false;
+    }
+    return true;
+}
+
+bool
+RegExpDisjunction::IsAnchoredAtEnd()
+{
+    const RegExpTreeVector &alternatives = this->alternatives();
+    for (size_t i = 0; i < alternatives.length(); i++) {
+        if (!alternatives[i]->IsAnchoredAtEnd())
+            return false;
+    }
+    return true;
+}
+
+// ----------------------------------------------------------------------------
+// RegExpAlternative
+
+static int IncreaseBy(int previous, int increase)
+{
+    if (RegExpTree::kInfinity - previous < increase)
+        return RegExpTree::kInfinity;
+    return previous + increase;
+}
+
+RegExpAlternative::RegExpAlternative(RegExpTreeVector *nodes)
+  : nodes_(nodes),
+    min_match_(0),
+    max_match_(0)
+{
+    JS_ASSERT(nodes->length() > 1);
+    for (size_t i = 0; i < nodes->length(); i++) {
+        RegExpTree* node = (*nodes)[i];
+        int node_min_match = node->min_match();
+        min_match_ = IncreaseBy(min_match_, node_min_match);
+        int node_max_match = node->max_match();
+        max_match_ = IncreaseBy(max_match_, node_max_match);
+    }
+}
+
+Interval
+RegExpAlternative::CaptureRegisters()
+{
+    return ListCaptureRegisters(nodes());
+}
+
+bool
+RegExpAlternative::IsAnchoredAtStart()
+{
+    const RegExpTreeVector &nodes = this->nodes();
+    for (size_t i = 0; i < nodes.length(); i++) {
+        RegExpTree *node = nodes[i];
+        if (node->IsAnchoredAtStart()) { return true; }
+        if (node->max_match() > 0) { return false; }
+    }
+    return false;
+}
+
+bool
+RegExpAlternative::IsAnchoredAtEnd()
+{
+    const RegExpTreeVector &nodes = this->nodes();
+    for (int i = nodes.length() - 1; i >= 0; i--) {
+        RegExpTree *node = nodes[i];
+        if (node->IsAnchoredAtEnd()) { return true; }
+        if (node->max_match() > 0) { return false; }
+    }
+    return false;
+}
+
+// ----------------------------------------------------------------------------
+// RegExpAssertion
+
+bool
+RegExpAssertion::IsAnchoredAtStart()
+{
+    return assertion_type() == RegExpAssertion::START_OF_INPUT;
+}
+
+bool
+RegExpAssertion::IsAnchoredAtEnd()
+{
+    return assertion_type() == RegExpAssertion::END_OF_INPUT;
+}
+
+// ----------------------------------------------------------------------------
+// RegExpCharacterClass
+
+void
+RegExpCharacterClass::AppendToText(RegExpText* text)
+{
+    text->AddElement(TextElement::CharClass(this));
+}
+
+CharacterRangeVector &
+CharacterSet::ranges(LifoAlloc *alloc)
+{
+    if (ranges_ == nullptr) {
+        ranges_ = alloc->newInfallible<CharacterRangeVector>(*alloc);
+        CharacterRange::AddClassEscape(alloc, standard_set_type_, ranges_);
+    }
+    return *ranges_;
+}
+
+// ----------------------------------------------------------------------------
+// RegExpAtom
+
+void
+RegExpAtom::AppendToText(RegExpText* text)
+{
+    text->AddElement(TextElement::Atom(this));
+}
+
+// ----------------------------------------------------------------------------
+// RegExpText
+
+void
+RegExpText::AppendToText(RegExpText* text)
+{
+    for (size_t i = 0; i < elements().length(); i++)
+        text->AddElement(elements()[i]);
+}
+
+// ----------------------------------------------------------------------------
+// RegExpQuantifier
+
+Interval
+RegExpQuantifier::CaptureRegisters()
+{
+    return body()->CaptureRegisters();
+}
+
+// ----------------------------------------------------------------------------
+// RegExpCapture
+
+bool
+RegExpCapture::IsAnchoredAtStart()
+{
+    return body()->IsAnchoredAtStart();
+}
+
+bool
+RegExpCapture::IsAnchoredAtEnd()
+{
+    return body()->IsAnchoredAtEnd();
+}
+
+Interval
+RegExpCapture::CaptureRegisters()
+{
+    Interval self(StartRegister(index()), EndRegister(index()));
+    return self.Union(body()->CaptureRegisters());
+}
+
+// ----------------------------------------------------------------------------
+// RegExpLookahead
+
+Interval
+RegExpLookahead::CaptureRegisters()
+{
+    return body()->CaptureRegisters();
+}
+
+bool
+RegExpLookahead::IsAnchoredAtStart()
+{
+    return is_positive() && body()->IsAnchoredAtStart();
+}
new file mode 100644
--- /dev/null
+++ b/js/src/irregexp/RegExpAST.h
@@ -0,0 +1,439 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99: */
+
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_REGEXP_AST_H_
+#define V8_REGEXP_AST_H_
+
+#include "irregexp/RegExpEngine.h"
+
+namespace js {
+namespace irregexp {
+
+class RegExpCompiler;
+class RegExpNode;
+
+class RegExpVisitor
+{
+  public:
+    virtual ~RegExpVisitor() { }
+#define MAKE_CASE(Name)                                         \
+    virtual void* Visit##Name(RegExp##Name*, void* data) = 0;
+    FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
+#undef MAKE_CASE
+};
+
+class RegExpTree
+{
+  public:
+    static const int kInfinity = INT32_MAX;
+    virtual ~RegExpTree() {}
+    virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                               RegExpNode* on_success) = 0;
+    virtual bool IsTextElement() { return false; }
+    virtual bool IsAnchoredAtStart() { return false; }
+    virtual bool IsAnchoredAtEnd() { return false; }
+    virtual int min_match() = 0;
+    virtual int max_match() = 0;
+    // Returns the interval of registers used for captures within this
+    // expression.
+    virtual Interval CaptureRegisters() { return Interval::Empty(); }
+    virtual void AppendToText(RegExpText* text) {
+        MOZ_ASSUME_UNREACHABLE("Bad call");
+    }
+#define MAKE_ASTYPE(Name)                                               \
+    virtual RegExp##Name* As##Name();                                   \
+    virtual bool Is##Name();
+    FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ASTYPE)
+#undef MAKE_ASTYPE
+};
+
+typedef Vector<RegExpTree *, 1, LifoAllocPolicy<Infallible> > RegExpTreeVector;
+
+class RegExpDisjunction : public RegExpTree
+{
+  public:
+    explicit RegExpDisjunction(RegExpTreeVector *alternatives);
+    virtual void* Accept(RegExpVisitor* visitor, void* data);
+    virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                               RegExpNode* on_success);
+    virtual RegExpDisjunction* AsDisjunction();
+    virtual Interval CaptureRegisters();
+    virtual bool IsDisjunction();
+    virtual bool IsAnchoredAtStart();
+    virtual bool IsAnchoredAtEnd();
+    virtual int min_match() { return min_match_; }
+    virtual int max_match() { return max_match_; }
+
+    const RegExpTreeVector &alternatives() { return *alternatives_; }
+
+  private:
+    RegExpTreeVector *alternatives_;
+    int min_match_;
+    int max_match_;
+};
+
+class RegExpAlternative : public RegExpTree
+{
+  public:
+    explicit RegExpAlternative(RegExpTreeVector *nodes);
+    virtual void* Accept(RegExpVisitor* visitor, void* data);
+    virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                               RegExpNode* on_success);
+    virtual RegExpAlternative* AsAlternative();
+    virtual Interval CaptureRegisters();
+    virtual bool IsAlternative();
+    virtual bool IsAnchoredAtStart();
+    virtual bool IsAnchoredAtEnd();
+    virtual int min_match() { return min_match_; }
+    virtual int max_match() { return max_match_; }
+
+    const RegExpTreeVector &nodes() { return *nodes_; }
+
+  private:
+    RegExpTreeVector *nodes_;
+    int min_match_;
+    int max_match_;
+};
+
+class RegExpAssertion : public RegExpTree {
+ public:
+  enum AssertionType {
+    START_OF_LINE,
+    START_OF_INPUT,
+    END_OF_LINE,
+    END_OF_INPUT,
+    BOUNDARY,
+    NON_BOUNDARY
+  };
+  explicit RegExpAssertion(AssertionType type) : assertion_type_(type) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                             RegExpNode* on_success);
+  virtual RegExpAssertion* AsAssertion();
+  virtual bool IsAssertion();
+  virtual bool IsAnchoredAtStart();
+  virtual bool IsAnchoredAtEnd();
+  virtual int min_match() { return 0; }
+  virtual int max_match() { return 0; }
+  AssertionType assertion_type() { return assertion_type_; }
+ private:
+  AssertionType assertion_type_;
+};
+
+class CharacterSet
+{
+  public:
+    explicit CharacterSet(jschar standard_set_type)
+      : ranges_(nullptr),
+        standard_set_type_(standard_set_type)
+    {}
+    explicit CharacterSet(CharacterRangeVector *ranges)
+      : ranges_(ranges),
+        standard_set_type_(0)
+    {}
+
+    CharacterRangeVector &ranges(LifoAlloc *alloc);
+    jschar standard_set_type() { return standard_set_type_; }
+    void set_standard_set_type(jschar special_set_type) {
+        standard_set_type_ = special_set_type;
+    }
+    bool is_standard() { return standard_set_type_ != 0; }
+    void Canonicalize();
+
+  private:
+    CharacterRangeVector *ranges_;
+
+    // If non-zero, the value represents a standard set (e.g., all whitespace
+    // characters) without having to expand the ranges.
+    jschar standard_set_type_;
+};
+
+class RegExpCharacterClass : public RegExpTree
+{
+  public:
+    RegExpCharacterClass(CharacterRangeVector *ranges, bool is_negated)
+      : set_(ranges),
+        is_negated_(is_negated)
+    {}
+
+    explicit RegExpCharacterClass(jschar type)
+      : set_(type),
+        is_negated_(false)
+    {}
+
+    virtual void* Accept(RegExpVisitor* visitor, void* data);
+    virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                               RegExpNode* on_success);
+    virtual RegExpCharacterClass* AsCharacterClass();
+    virtual bool IsCharacterClass();
+    virtual bool IsTextElement() { return true; }
+    virtual int min_match() { return 1; }
+    virtual int max_match() { return 1; }
+    virtual void AppendToText(RegExpText* text);
+
+    CharacterSet character_set() { return set_; }
+
+    // TODO(lrn): Remove need for complex version if is_standard that
+    // recognizes a mangled standard set and just do { return set_.is_special(); }
+    bool is_standard(LifoAlloc *alloc);
+
+    // Returns a value representing the standard character set if is_standard()
+    // returns true.
+    // Currently used values are:
+    // s : unicode whitespace
+    // S : unicode non-whitespace
+    // w : ASCII word character (digit, letter, underscore)
+    // W : non-ASCII word character
+    // d : ASCII digit
+    // D : non-ASCII digit
+    // . : non-unicode non-newline
+    // * : All characters
+    jschar standard_type() { return set_.standard_set_type(); }
+
+    CharacterRangeVector &ranges(LifoAlloc *alloc) { return set_.ranges(alloc); }
+    bool is_negated() { return is_negated_; }
+
+  private:
+    CharacterSet set_;
+    bool is_negated_;
+};
+
+typedef Vector<jschar, 10, LifoAllocPolicy<Infallible> > CharacterVector;
+
+class RegExpAtom : public RegExpTree
+{
+  public:
+    explicit RegExpAtom(CharacterVector *data)
+      : data_(data)
+    {}
+
+    virtual void* Accept(RegExpVisitor* visitor, void* data);
+    virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                               RegExpNode* on_success);
+    virtual RegExpAtom* AsAtom();
+    virtual bool IsAtom();
+    virtual bool IsTextElement() { return true; }
+    virtual int min_match() { return data_->length(); }
+    virtual int max_match() { return data_->length(); }
+    virtual void AppendToText(RegExpText* text);
+
+    const CharacterVector &data() { return *data_; }
+    int length() { return data_->length(); }
+
+  private:
+    CharacterVector *data_;
+};
+
+class RegExpText : public RegExpTree
+{
+  public:
+    explicit RegExpText(LifoAlloc *alloc)
+      : elements_(*alloc), length_(0)
+    {}
+
+    virtual void* Accept(RegExpVisitor* visitor, void* data);
+    virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                               RegExpNode* on_success);
+    virtual RegExpText* AsText();
+    virtual bool IsText();
+    virtual bool IsTextElement() { return true; }
+    virtual int min_match() { return length_; }
+    virtual int max_match() { return length_; }
+    virtual void AppendToText(RegExpText* text);
+
+    void AddElement(TextElement elm)  {
+        elements_.append(elm);
+        length_ += elm.length();
+    }
+    const TextElementVector &elements() { return elements_; }
+
+  private:
+    TextElementVector elements_;
+    int length_;
+};
+
+class RegExpQuantifier : public RegExpTree
+{
+  public:
+    enum QuantifierType { GREEDY, NON_GREEDY, POSSESSIVE };
+    RegExpQuantifier(int min, int max, QuantifierType type, RegExpTree* body)
+      : body_(body),
+        min_(min),
+        max_(max),
+        min_match_(min * body->min_match()),
+        quantifier_type_(type)
+    {
+        if (max > 0 && body->max_match() > kInfinity / max) {
+            max_match_ = kInfinity;
+        } else {
+            max_match_ = max * body->max_match();
+        }
+    }
+
+    virtual void* Accept(RegExpVisitor* visitor, void* data);
+    virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                               RegExpNode* on_success);
+    static RegExpNode* ToNode(int min,
+                              int max,
+                              bool is_greedy,
+                              RegExpTree* body,
+                              RegExpCompiler* compiler,
+                              RegExpNode* on_success,
+                              bool not_at_start = false);
+    virtual RegExpQuantifier* AsQuantifier();
+    virtual Interval CaptureRegisters();
+    virtual bool IsQuantifier();
+    virtual int min_match() { return min_match_; }
+    virtual int max_match() { return max_match_; }
+    int min() { return min_; }
+    int max() { return max_; }
+    bool is_possessive() { return quantifier_type_ == POSSESSIVE; }
+    bool is_non_greedy() { return quantifier_type_ == NON_GREEDY; }
+    bool is_greedy() { return quantifier_type_ == GREEDY; }
+    RegExpTree* body() { return body_; }
+
+  private:
+    RegExpTree* body_;
+    int min_;
+    int max_;
+    int min_match_;
+    int max_match_;
+    QuantifierType quantifier_type_;
+};
+
+class RegExpCapture : public RegExpTree
+{
+  public:
+    explicit RegExpCapture(RegExpTree* body, int index)
+      : body_(body), index_(index)
+    {}
+
+    virtual void* Accept(RegExpVisitor* visitor, void* data);
+    virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                               RegExpNode* on_success);
+    static RegExpNode* ToNode(RegExpTree* body,
+                              int index,
+                              RegExpCompiler* compiler,
+                              RegExpNode* on_success);
+    virtual RegExpCapture* AsCapture();
+    virtual bool IsAnchoredAtStart();
+    virtual bool IsAnchoredAtEnd();
+    virtual Interval CaptureRegisters();
+    virtual bool IsCapture();
+    virtual int min_match() { return body_->min_match(); }
+    virtual int max_match() { return body_->max_match(); }
+    RegExpTree* body() { return body_; }
+    int index() { return index_; }
+    static int StartRegister(int index) { return index * 2; }
+    static int EndRegister(int index) { return index * 2 + 1; }
+
+  private:
+    RegExpTree* body_;
+    int index_;
+};
+
+class RegExpLookahead : public RegExpTree
+{
+  public:
+    RegExpLookahead(RegExpTree* body,
+                    bool is_positive,
+                    int capture_count,
+                    int capture_from)
+      : body_(body),
+        is_positive_(is_positive),
+        capture_count_(capture_count),
+        capture_from_(capture_from)
+    {}
+
+    virtual void* Accept(RegExpVisitor* visitor, void* data);
+    virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                               RegExpNode* on_success);
+    virtual RegExpLookahead* AsLookahead();
+    virtual Interval CaptureRegisters();
+    virtual bool IsLookahead();
+    virtual bool IsAnchoredAtStart();
+    virtual int min_match() { return 0; }
+    virtual int max_match() { return 0; }
+    RegExpTree* body() { return body_; }
+    bool is_positive() { return is_positive_; }
+    int capture_count() { return capture_count_; }
+    int capture_from() { return capture_from_; }
+
+  private:
+    RegExpTree* body_;
+    bool is_positive_;
+    int capture_count_;
+    int capture_from_;
+};
+
+typedef Vector<RegExpCapture *, 1, LifoAllocPolicy<Infallible> > RegExpCaptureVector;
+
+class RegExpBackReference : public RegExpTree
+{
+  public:
+    explicit RegExpBackReference(RegExpCapture* capture)
+      : capture_(capture)
+    {}
+
+    virtual void* Accept(RegExpVisitor* visitor, void* data);
+    virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                               RegExpNode* on_success);
+    virtual RegExpBackReference* AsBackReference();
+    virtual bool IsBackReference();
+    virtual int min_match() { return 0; }
+    virtual int max_match() { return capture_->max_match(); }
+    int index() { return capture_->index(); }
+    RegExpCapture* capture() { return capture_; }
+  private:
+    RegExpCapture* capture_;
+};
+
+class RegExpEmpty : public RegExpTree
+{
+  public:
+    RegExpEmpty()
+    {}
+
+    virtual void* Accept(RegExpVisitor* visitor, void* data);
+    virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                               RegExpNode* on_success);
+    virtual RegExpEmpty* AsEmpty();
+    virtual bool IsEmpty();
+    virtual int min_match() { return 0; }
+    virtual int max_match() { return 0; }
+    static RegExpEmpty* GetInstance() {
+        static RegExpEmpty instance;
+        return &instance;
+    }
+};
+
+} } // namespace js::irregexp
+
+#endif  // V8_REGEXP_AST_H_
new file mode 100644
--- /dev/null
+++ b/js/src/irregexp/RegExpBytecode.h
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99: */
+
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_BYTECODES_IRREGEXP_H_
+#define V8_BYTECODES_IRREGEXP_H_
+
+namespace js {
+namespace irregexp {
+
+const int BYTECODE_MASK = 0xff;
+
+// The first argument is packed in with the byte code in one word, so it
+// has 24 bits, but it can be positive and negative so only use 23 bits for
+// positive values.
+const unsigned int MAX_FIRST_ARG = 0x7fffffu;
+const int BYTECODE_SHIFT = 8;
+
+#define BYTECODE_ITERATOR(V)                                                   \
+V(BREAK,              0, 4)   /* bc8                                        */ \
+V(PUSH_CP,            1, 4)   /* bc8 pad24                                  */ \
+V(PUSH_BT,            2, 8)   /* bc8 pad24 offset32                         */ \
+V(PUSH_REGISTER,      3, 4)   /* bc8 reg_idx24                              */ \
+V(SET_REGISTER_TO_CP, 4, 8)   /* bc8 reg_idx24 offset32                     */ \
+V(SET_CP_TO_REGISTER, 5, 4)   /* bc8 reg_idx24                              */ \
+V(SET_REGISTER_TO_SP, 6, 4)   /* bc8 reg_idx24                              */ \
+V(SET_SP_TO_REGISTER, 7, 4)   /* bc8 reg_idx24                              */ \
+V(SET_REGISTER,       8, 8)   /* bc8 reg_idx24 value32                      */ \
+V(ADVANCE_REGISTER,   9, 8)   /* bc8 reg_idx24 value32                      */ \
+V(POP_CP,            10, 4)   /* bc8 pad24                                  */ \
+V(POP_BT,            11, 4)   /* bc8 pad24                                  */ \
+V(POP_REGISTER,      12, 4)   /* bc8 reg_idx24                              */ \
+V(FAIL,              13, 4)   /* bc8 pad24                                  */ \
+V(SUCCEED,           14, 4)   /* bc8 pad24                                  */ \
+V(ADVANCE_CP,        15, 4)   /* bc8 offset24                               */ \
+V(GOTO,              16, 8)   /* bc8 pad24 addr32                           */ \
+V(LOAD_CURRENT_CHAR, 17, 8)   /* bc8 offset24 addr32                        */ \
+V(LOAD_CURRENT_CHAR_UNCHECKED, 18, 4) /* bc8 offset24                       */ \
+V(LOAD_2_CURRENT_CHARS, 19, 8) /* bc8 offset24 addr32                       */ \
+V(LOAD_2_CURRENT_CHARS_UNCHECKED, 20, 4) /* bc8 offset24                    */ \
+V(LOAD_4_CURRENT_CHARS, 21, 8) /* bc8 offset24 addr32                       */ \
+V(LOAD_4_CURRENT_CHARS_UNCHECKED, 22, 4) /* bc8 offset24                    */ \
+V(CHECK_4_CHARS,     23, 12)  /* bc8 pad24 uint32 addr32                    */ \
+V(CHECK_CHAR,        24, 8)   /* bc8 pad8 uint16 addr32                     */ \
+V(CHECK_NOT_4_CHARS, 25, 12)  /* bc8 pad24 uint32 addr32                    */ \
+V(CHECK_NOT_CHAR,    26, 8)   /* bc8 pad8 uint16 addr32                     */ \
+V(AND_CHECK_4_CHARS, 27, 16)  /* bc8 pad24 uint32 uint32 addr32             */ \
+V(AND_CHECK_CHAR,    28, 12)  /* bc8 pad8 uint16 uint32 addr32              */ \
+V(AND_CHECK_NOT_4_CHARS, 29, 16) /* bc8 pad24 uint32 uint32 addr32          */ \
+V(AND_CHECK_NOT_CHAR, 30, 12) /* bc8 pad8 uint16 uint32 addr32              */ \
+V(MINUS_AND_CHECK_NOT_CHAR, 31, 12) /* bc8 pad8 uc16 uc16 uc16 addr32       */ \
+V(CHECK_CHAR_IN_RANGE, 32, 12) /* bc8 pad24 uc16 uc16 addr32                */ \
+V(CHECK_CHAR_NOT_IN_RANGE, 33, 12) /* bc8 pad24 uc16 uc16 addr32            */ \
+V(CHECK_BIT_IN_TABLE, 34, 24) /* bc8 pad24 addr32 bits128                   */ \
+V(CHECK_LT,          35, 8)   /* bc8 pad8 uc16 addr32                       */ \
+V(CHECK_GT,          36, 8)   /* bc8 pad8 uc16 addr32                       */ \
+V(CHECK_NOT_BACK_REF, 37, 8)  /* bc8 reg_idx24 addr32                       */ \
+V(CHECK_NOT_BACK_REF_NO_CASE, 38, 8) /* bc8 reg_idx24 addr32                */ \
+V(CHECK_NOT_REGS_EQUAL, 39, 12) /* bc8 regidx24 reg_idx32 addr32            */ \
+V(CHECK_REGISTER_LT, 40, 12)  /* bc8 reg_idx24 value32 addr32               */ \
+V(CHECK_REGISTER_GE, 41, 12)  /* bc8 reg_idx24 value32 addr32               */ \
+V(CHECK_REGISTER_EQ_POS, 42, 8) /* bc8 reg_idx24 addr32                     */ \
+V(CHECK_AT_START,    43, 8)   /* bc8 pad24 addr32                           */ \
+V(CHECK_NOT_AT_START, 44, 8)  /* bc8 pad24 addr32                           */ \
+V(CHECK_GREEDY,      45, 8)   /* bc8 pad24 addr32                           */ \
+V(ADVANCE_CP_AND_GOTO, 46, 8) /* bc8 offset24 addr32                        */ \
+V(SET_CURRENT_POSITION_FROM_END, 47, 4) /* bc8 idx24                        */
+
+#define DECLARE_BYTECODES(name, code, length) \
+  static const int BC_##name = code;
+BYTECODE_ITERATOR(DECLARE_BYTECODES)
+#undef DECLARE_BYTECODES
+
+#define DECLARE_BYTECODE_LENGTH(name, code, length) \
+  static const int BC_##name##_LENGTH = length;
+BYTECODE_ITERATOR(DECLARE_BYTECODE_LENGTH)
+#undef DECLARE_BYTECODE_LENGTH
+
+} } // namespace js::irregexp
+
+#endif  // V8_BYTECODES_IRREGEXP_H_
new file mode 100644
--- /dev/null
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -0,0 +1,4766 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99: */
+
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "irregexp/RegExpEngine.h"
+
+#include "irregexp/NativeRegExpMacroAssembler.h"
+#include "irregexp/RegExpMacroAssembler.h"
+#include "jit/JitCommon.h"
+
+using namespace js;
+using namespace js::irregexp;
+
+using mozilla::ArrayLength;
+using mozilla::DebugOnly;
+using mozilla::Maybe;
+
+#define DEFINE_ACCEPT(Type)                                          \
+    void Type##Node::Accept(NodeVisitor* visitor) {                  \
+        visitor->Visit##Type(this);                                  \
+    }
+FOR_EACH_NODE_TYPE(DEFINE_ACCEPT)
+#undef DEFINE_ACCEPT
+
+void LoopChoiceNode::Accept(NodeVisitor* visitor) {
+    visitor->VisitLoopChoice(this);
+}
+
+static const int kMaxLookaheadForBoyerMoore = 8;
+
+RegExpNode::RegExpNode(LifoAlloc *alloc)
+  : replacement_(nullptr), trace_count_(0), alloc_(alloc)
+{
+    bm_info_[0] = bm_info_[1] = nullptr;
+}
+
+// -------------------------------------------------------------------
+// CharacterRange
+
+// The '2' variant has inclusive from and exclusive to.
+// This covers \s as defined in ECMA-262 5.1, 15.10.2.12,
+// which include WhiteSpace (7.2) or LineTerminator (7.3) values.
+static const int kSpaceRanges[] = { '\t', '\r' + 1, ' ', ' ' + 1,
+    0x00A0, 0x00A1, 0x1680, 0x1681, 0x180E, 0x180F, 0x2000, 0x200B,
+    0x2028, 0x202A, 0x202F, 0x2030, 0x205F, 0x2060, 0x3000, 0x3001,
+    0xFEFF, 0xFF00, 0x10000 };
+static const int kSpaceRangeCount = ArrayLength(kSpaceRanges);
+
+static const int kWordRanges[] = {
+    '0', '9' + 1, 'A', 'Z' + 1, '_', '_' + 1, 'a', 'z' + 1, 0x10000 };
+static const int kWordRangeCount = ArrayLength(kWordRanges);
+static const int kDigitRanges[] = { '0', '9' + 1, 0x10000 };
+static const int kDigitRangeCount = ArrayLength(kDigitRanges);
+static const int kSurrogateRanges[] = { 0xd800, 0xe000, 0x10000 };
+static const int kSurrogateRangeCount = ArrayLength(kSurrogateRanges);
+static const int kLineTerminatorRanges[] = { 0x000A, 0x000B, 0x000D, 0x000E,
+    0x2028, 0x202A, 0x10000 };
+static const int kLineTerminatorRangeCount = ArrayLength(kLineTerminatorRanges);
+static const unsigned kMaxOneByteCharCode = 0xff;
+static const int kMaxUtf16CodeUnit = 0xffff;
+
+static jschar
+MaximumCharacter(bool ascii)
+{
+    return ascii ? kMaxOneByteCharCode : kMaxUtf16CodeUnit;
+}
+
+static void
+AddClass(const int* elmv, int elmc,
+         CharacterRangeVector *ranges)
+{
+    elmc--;
+    JS_ASSERT(elmv[elmc] == 0x10000);
+    for (int i = 0; i < elmc; i += 2) {
+        JS_ASSERT(elmv[i] < elmv[i + 1]);
+        ranges->append(CharacterRange(elmv[i], elmv[i + 1] - 1));
+    }
+}
+
+static void
+AddClassNegated(const int *elmv,
+                int elmc,
+                CharacterRangeVector *ranges)
+{
+    elmc--;
+    JS_ASSERT(elmv[elmc] == 0x10000);
+    JS_ASSERT(elmv[0] != 0x0000);
+    JS_ASSERT(elmv[elmc-1] != kMaxUtf16CodeUnit);
+    jschar last = 0x0000;
+    for (int i = 0; i < elmc; i += 2) {
+        JS_ASSERT(last <= elmv[i] - 1);
+        JS_ASSERT(elmv[i] < elmv[i + 1]);
+        ranges->append(CharacterRange(last, elmv[i] - 1));
+        last = elmv[i + 1];
+    }
+    ranges->append(CharacterRange(last, kMaxUtf16CodeUnit));
+}
+
+void
+CharacterRange::AddClassEscape(LifoAlloc *alloc, jschar type,
+			       CharacterRangeVector *ranges)
+{
+    switch (type) {
+      case 's':
+        AddClass(kSpaceRanges, kSpaceRangeCount, ranges);
+        break;
+      case 'S':
+        AddClassNegated(kSpaceRanges, kSpaceRangeCount, ranges);
+        break;
+      case 'w':
+        AddClass(kWordRanges, kWordRangeCount, ranges);
+        break;
+      case 'W':
+        AddClassNegated(kWordRanges, kWordRangeCount, ranges);
+        break;
+      case 'd':
+        AddClass(kDigitRanges, kDigitRangeCount, ranges);
+        break;
+      case 'D':
+        AddClassNegated(kDigitRanges, kDigitRangeCount, ranges);
+        break;
+      case '.':
+        AddClassNegated(kLineTerminatorRanges, kLineTerminatorRangeCount, ranges);
+        break;
+        // This is not a character range as defined by the spec but a
+        // convenient shorthand for a character class that matches any
+        // character.
+      case '*':
+        ranges->append(CharacterRange::Everything());
+        break;
+        // This is the set of characters matched by the $ and ^ symbols
+        // in multiline mode.
+      case 'n':
+        AddClass(kLineTerminatorRanges, kLineTerminatorRangeCount, ranges);
+        break;
+      default:
+        MOZ_ASSUME_UNREACHABLE("Bad character class escape");
+    }
+}
+
+// We need to check for the following characters: 0x39c 0x3bc 0x178.
+static inline bool
+RangeContainsLatin1Equivalents(CharacterRange range)
+{
+    // TODO(dcarney): this could be a lot more efficient.
+    return range.Contains(0x39c) || range.Contains(0x3bc) || range.Contains(0x178);
+}
+
+static bool
+RangesContainLatin1Equivalents(const CharacterRangeVector &ranges)
+{
+    for (size_t i = 0; i < ranges.length(); i++) {
+        // TODO(dcarney): this could be a lot more efficient.
+        if (RangeContainsLatin1Equivalents(ranges[i]))
+            return true;
+    }
+    return false;
+}
+
+static const size_t kEcma262UnCanonicalizeMaxWidth = 4;
+
+// Returns the number of characters in the equivalence class, omitting those
+// that cannot occur in the source string because it is ASCII.
+static int
+GetCaseIndependentLetters(jschar character,
+                          bool ascii_subject,
+                          jschar *letters)
+{
+    JS_ASSERT(!ascii_subject);
+
+    jschar lower = unicode::ToLowerCase(character);
+    jschar upper = unicode::ToUpperCase(character);
+
+    letters[0] = character;
+
+    if (lower != character) {
+        letters[1] = lower;
+        if (upper != character && upper != lower) {
+            letters[2] = upper;
+            return 3;
+        }
+        return 2;
+    }
+    if (upper != character) {
+        letters[1] = upper;
+        return 2;
+    }
+    return 1;
+}
+
+void
+CharacterRange::AddCaseEquivalents(bool is_ascii, CharacterRangeVector *ranges)
+{
+    jschar bottom = from();
+    jschar top = to();
+
+    if (is_ascii && !RangeContainsLatin1Equivalents(*this)) {
+        if (bottom > kMaxOneByteCharCode)
+            return;
+        if (top > kMaxOneByteCharCode)
+            top = kMaxOneByteCharCode;
+    }
+
+    for (jschar c = bottom;; c++) {
+        jschar chars[kEcma262UnCanonicalizeMaxWidth];
+        size_t length = GetCaseIndependentLetters(c, is_ascii, chars);
+
+        for (size_t i = 0; i < length; i++) {
+            jschar other = chars[i];
+            if (other == c)
+                continue;
+
+            // Try to combine with an existing range.
+            bool found = false;
+            for (size_t i = 0; i < ranges->length(); i++) {
+                CharacterRange &range = (*ranges)[i];
+                if (range.Contains(other)) {
+                    found = true;
+                    break;
+                } else if (other == range.from() - 1) {
+                    range.set_from(other);
+                    found = true;
+                    break;
+                } else if (other == range.to() + 1) {
+                    range.set_to(other);
+                    found = true;
+                    break;
+                }
+            }
+
+            if (!found)
+                ranges->append(CharacterRange::Singleton(other));
+        }
+
+        if (c == top)
+            break;
+    }
+}
+
+static bool
+CompareInverseRanges(const CharacterRangeVector &ranges, const int *special_class, size_t length)
+{
+    length--;  // Remove final 0x10000.
+    JS_ASSERT(special_class[length] == 0x10000);
+    JS_ASSERT(ranges.length() != 0);
+    JS_ASSERT(length != 0);
+    JS_ASSERT(special_class[0] != 0);
+    if (ranges.length() != (length >> 1) + 1)
+        return false;
+    CharacterRange range = ranges[0];
+    if (range.from() != 0)
+        return false;
+    for (size_t i = 0; i < length; i += 2) {
+        if (special_class[i] != (range.to() + 1))
+            return false;
+        range = ranges[(i >> 1) + 1];
+        if (special_class[i+1] != range.from())
+            return false;
+    }
+    if (range.to() != 0xffff)
+        return false;
+    return true;
+}
+
+static bool
+CompareRanges(const CharacterRangeVector &ranges, const int *special_class, size_t length)
+{
+    length--;  // Remove final 0x10000.
+    JS_ASSERT(special_class[length] == 0x10000);
+    if (ranges.length() * 2 != length)
+        return false;
+    for (size_t i = 0; i < length; i += 2) {
+        CharacterRange range = ranges[i >> 1];
+        if (range.from() != special_class[i] || range.to() != special_class[i + 1] - 1)
+            return false;
+    }
+    return true;
+}
+
+bool
+RegExpCharacterClass::is_standard(LifoAlloc *alloc)
+{
+    // TODO(lrn): Remove need for this function, by not throwing away information
+    // along the way.
+    if (is_negated_)
+        return false;
+    if (set_.is_standard())
+        return true;
+    if (CompareRanges(set_.ranges(alloc), kSpaceRanges, kSpaceRangeCount)) {
+        set_.set_standard_set_type('s');
+        return true;
+    }
+    if (CompareInverseRanges(set_.ranges(alloc), kSpaceRanges, kSpaceRangeCount)) {
+        set_.set_standard_set_type('S');
+        return true;
+    }
+    if (CompareInverseRanges(set_.ranges(alloc),
+                             kLineTerminatorRanges,
+                             kLineTerminatorRangeCount)) {
+        set_.set_standard_set_type('.');
+        return true;
+    }
+    if (CompareRanges(set_.ranges(alloc),
+                      kLineTerminatorRanges,
+                      kLineTerminatorRangeCount)) {
+        set_.set_standard_set_type('n');
+        return true;
+    }
+    if (CompareRanges(set_.ranges(alloc), kWordRanges, kWordRangeCount)) {
+        set_.set_standard_set_type('w');
+        return true;
+    }
+    if (CompareInverseRanges(set_.ranges(alloc), kWordRanges, kWordRangeCount)) {
+        set_.set_standard_set_type('W');
+        return true;
+    }
+    return false;
+}
+
+bool
+CharacterRange::IsCanonical(const CharacterRangeVector &ranges)
+{
+    int n = ranges.length();
+    if (n <= 1)
+        return true;
+
+    int max = ranges[0].to();
+    for (int i = 1; i < n; i++) {
+        CharacterRange next_range = ranges[i];
+        if (next_range.from() <= max + 1)
+            return false;
+        max = next_range.to();
+    }
+    return true;
+}
+
+// Move a number of elements in a zonelist to another position
+// in the same list. Handles overlapping source and target areas.
+static
+void MoveRanges(CharacterRangeVector &list, int from, int to, int count)
+{
+    // Ranges are potentially overlapping.
+    if (from < to) {
+        for (int i = count - 1; i >= 0; i--)
+            list[to + i] = list[from + i];
+    } else {
+        for (int i = 0; i < count; i++)
+            list[to + i] = list[from + i];
+    }
+}
+
+static int
+InsertRangeInCanonicalList(CharacterRangeVector &list,
+                           int count,
+                           CharacterRange insert)
+{
+    // Inserts a range into list[0..count[, which must be sorted
+    // by from value and non-overlapping and non-adjacent, using at most
+    // list[0..count] for the result. Returns the number of resulting
+    // canonicalized ranges. Inserting a range may collapse existing ranges into
+    // fewer ranges, so the return value can be anything in the range 1..count+1.
+    jschar from = insert.from();
+    jschar to = insert.to();
+    int start_pos = 0;
+    int end_pos = count;
+    for (int i = count - 1; i >= 0; i--) {
+        CharacterRange current = list[i];
+        if (current.from() > to + 1) {
+            end_pos = i;
+        } else if (current.to() + 1 < from) {
+            start_pos = i + 1;
+            break;
+        }
+    }
+
+    // Inserted range overlaps, or is adjacent to, ranges at positions
+    // [start_pos..end_pos[. Ranges before start_pos or at or after end_pos are
+    // not affected by the insertion.
+    // If start_pos == end_pos, the range must be inserted before start_pos.
+    // if start_pos < end_pos, the entire range from start_pos to end_pos
+    // must be merged with the insert range.
+
+    if (start_pos == end_pos) {
+        // Insert between existing ranges at position start_pos.
+        if (start_pos < count) {
+            MoveRanges(list, start_pos, start_pos + 1, count - start_pos);
+        }
+        list[start_pos] = insert;
+        return count + 1;
+    }
+    if (start_pos + 1 == end_pos) {
+        // Replace single existing range at position start_pos.
+        CharacterRange to_replace = list[start_pos];
+        int new_from = Min(to_replace.from(), from);
+        int new_to = Max(to_replace.to(), to);
+        list[start_pos] = CharacterRange(new_from, new_to);
+        return count;
+    }
+    // Replace a number of existing ranges from start_pos to end_pos - 1.
+    // Move the remaining ranges down.
+
+    int new_from = Min(list[start_pos].from(), from);
+    int new_to = Max(list[end_pos - 1].to(), to);
+    if (end_pos < count) {
+        MoveRanges(list, end_pos, start_pos + 1, count - end_pos);
+    }
+    list[start_pos] = CharacterRange(new_from, new_to);
+    return count - (end_pos - start_pos) + 1;
+}
+
+void
+CharacterRange::Canonicalize(CharacterRangeVector &character_ranges)
+{
+    if (character_ranges.length() <= 1) return;
+    // Check whether ranges are already canonical (increasing, non-overlapping,
+    // non-adjacent).
+    int n = character_ranges.length();
+    int max = character_ranges[0].to();
+    int i = 1;
+    while (i < n) {
+        CharacterRange current = character_ranges[i];
+        if (current.from() <= max + 1) {
+            break;
+        }
+        max = current.to();
+        i++;
+    }
+    // Canonical until the i'th range. If that's all of them, we are done.
+    if (i == n) return;
+
+    // The ranges at index i and forward are not canonicalized. Make them so by
+    // doing the equivalent of insertion sort (inserting each into the previous
+    // list, in order).
+    // Notice that inserting a range can reduce the number of ranges in the
+    // result due to combining of adjacent and overlapping ranges.
+    int read = i;  // Range to insert.
+    size_t num_canonical = i;  // Length of canonicalized part of list.
+    do {
+        num_canonical = InsertRangeInCanonicalList(character_ranges,
+                                                   num_canonical,
+                                                   character_ranges[read]);
+        read++;
+    } while (read < n);
+
+    while (character_ranges.length() > num_canonical)
+        character_ranges.popBack();
+
+    JS_ASSERT(CharacterRange::IsCanonical(character_ranges));
+}
+
+// -------------------------------------------------------------------
+// SeqRegExpNode
+
+class VisitMarker
+{
+  public:
+    explicit VisitMarker(NodeInfo* info)
+      : info_(info)
+    {
+        JS_ASSERT(!info->visited);
+        info->visited = true;
+    }
+    ~VisitMarker() {
+        info_->visited = false;
+    }
+  private:
+    NodeInfo* info_;
+};
+
+RegExpNode *
+SeqRegExpNode::FilterASCII(int depth, bool ignore_case)
+{
+    if (info()->replacement_calculated)
+        return replacement();
+
+    if (depth < 0)
+        return this;
+
+    JS_ASSERT(!info()->visited);
+    VisitMarker marker(info());
+    return FilterSuccessor(depth - 1, ignore_case);
+}
+
+RegExpNode *
+SeqRegExpNode::FilterSuccessor(int depth, bool ignore_case)
+{
+    RegExpNode* next = on_success_->FilterASCII(depth - 1, ignore_case);
+    if (next == nullptr)
+        return set_replacement(nullptr);
+
+    on_success_ = next;
+    return set_replacement(this);
+}
+
+// -------------------------------------------------------------------
+// ActionNode
+
+int
+ActionNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start)
+{
+    if (budget <= 0)
+        return 0;
+    if (action_type_ == POSITIVE_SUBMATCH_SUCCESS)
+        return 0;  // Rewinds input!
+    return on_success()->EatsAtLeast(still_to_find,
+                                     budget - 1,
+                                     not_at_start);
+}
+
+void
+ActionNode::FillInBMInfo(int offset,
+                         int budget,
+                         BoyerMooreLookahead* bm,
+                         bool not_at_start)
+{
+    if (action_type_ == BEGIN_SUBMATCH)
+        bm->SetRest(offset);
+    else if (action_type_ != POSITIVE_SUBMATCH_SUCCESS)
+        on_success()->FillInBMInfo(offset, budget - 1, bm, not_at_start);
+    SaveBMInfo(bm, not_at_start, offset);
+}
+
+/* static */ ActionNode *
+ActionNode::SetRegister(int reg,
+                        int val,
+                        RegExpNode *on_success)
+{
+    ActionNode *result = on_success->alloc()->newInfallible<ActionNode>(SET_REGISTER, on_success);
+    result->data_.u_store_register.reg = reg;
+    result->data_.u_store_register.value = val;
+    return result;
+}
+
+/* static */ ActionNode *
+ActionNode::IncrementRegister(int reg, RegExpNode *on_success)
+{
+    ActionNode *result = on_success->alloc()->newInfallible<ActionNode>(INCREMENT_REGISTER, on_success);
+    result->data_.u_increment_register.reg = reg;
+    return result;
+}
+
+/* static */ ActionNode *
+ActionNode::StorePosition(int reg, bool is_capture, RegExpNode *on_success)
+{
+    ActionNode *result = on_success->alloc()->newInfallible<ActionNode>(STORE_POSITION, on_success);
+    result->data_.u_position_register.reg = reg;
+    result->data_.u_position_register.is_capture = is_capture;
+    return result;
+}
+
+/* static */ ActionNode *
+ActionNode::ClearCaptures(Interval range, RegExpNode *on_success)
+{
+    ActionNode *result = on_success->alloc()->newInfallible<ActionNode>(CLEAR_CAPTURES, on_success);
+    result->data_.u_clear_captures.range_from = range.from();
+    result->data_.u_clear_captures.range_to = range.to();
+    return result;
+}
+
+/* static */ ActionNode *
+ActionNode::BeginSubmatch(int stack_pointer_reg, int position_reg, RegExpNode *on_success)
+{
+    ActionNode *result = on_success->alloc()->newInfallible<ActionNode>(BEGIN_SUBMATCH, on_success);
+    result->data_.u_submatch.stack_pointer_register = stack_pointer_reg;
+    result->data_.u_submatch.current_position_register = position_reg;
+    return result;
+}
+
+/* static */ ActionNode *
+ActionNode::PositiveSubmatchSuccess(int stack_pointer_reg,
+                                    int restore_reg,
+                                    int clear_capture_count,
+                                    int clear_capture_from,
+                                    RegExpNode *on_success)
+{
+    ActionNode *result = on_success->alloc()->newInfallible<ActionNode>(POSITIVE_SUBMATCH_SUCCESS, on_success);
+    result->data_.u_submatch.stack_pointer_register = stack_pointer_reg;
+    result->data_.u_submatch.current_position_register = restore_reg;
+    result->data_.u_submatch.clear_register_count = clear_capture_count;
+    result->data_.u_submatch.clear_register_from = clear_capture_from;
+    return result;
+}
+
+/* static */ ActionNode *
+ActionNode::EmptyMatchCheck(int start_register,
+                            int repetition_register,
+                            int repetition_limit,
+                            RegExpNode *on_success)
+{
+    ActionNode *result = on_success->alloc()->newInfallible<ActionNode>(EMPTY_MATCH_CHECK, on_success);
+    result->data_.u_empty_match_check.start_register = start_register;
+    result->data_.u_empty_match_check.repetition_register = repetition_register;
+    result->data_.u_empty_match_check.repetition_limit = repetition_limit;
+    return result;
+}
+
+// -------------------------------------------------------------------
+// TextNode
+
+int
+TextNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start)
+{
+    int answer = Length();
+    if (answer >= still_to_find)
+        return answer;
+    if (budget <= 0)
+        return answer;
+
+    // We are not at start after this node so we set the last argument to 'true'.
+    return answer + on_success()->EatsAtLeast(still_to_find - answer,
+                                              budget - 1,
+                                              true);
+}
+
+int
+TextNode::GreedyLoopTextLength()
+{
+    TextElement elm = elements()[elements().length() - 1];
+    return elm.cp_offset() + elm.length();
+}
+
+RegExpNode *
+TextNode::FilterASCII(int depth, bool ignore_case)
+{
+    if (info()->replacement_calculated)
+        return replacement();
+
+    if (depth < 0)
+        return this;
+
+    JS_ASSERT(!info()->visited);
+    VisitMarker marker(info());
+    int element_count = elements().length();
+    for (int i = 0; i < element_count; i++) {
+        TextElement elm = elements()[i];
+        if (elm.text_type() == TextElement::ATOM) {
+            CharacterVector &quarks = const_cast<CharacterVector &>(elm.atom()->data());
+            for (size_t j = 0; j < quarks.length(); j++) {
+                uint16_t c = quarks[j];
+                if (c <= kMaxOneByteCharCode)
+                    continue;
+                if (!ignore_case)
+                    return set_replacement(nullptr);
+
+                // Here, we need to check for characters whose upper and lower cases
+                // are outside the Latin-1 range.
+                jschar chars[kEcma262UnCanonicalizeMaxWidth];
+                size_t length = GetCaseIndependentLetters(c, true, chars);
+                JS_ASSERT(length <= 1);
+
+                if (length == 0) {
+                    // Character is outside Latin-1 completely
+                    return set_replacement(nullptr);
+                }
+
+                // Convert quark to Latin-1 in place.
+                quarks[j] = chars[0];
+            }
+        } else {
+            JS_ASSERT(elm.text_type() == TextElement::CHAR_CLASS);
+            RegExpCharacterClass* cc = elm.char_class();
+
+            CharacterRangeVector &ranges = cc->ranges(alloc());
+            if (!CharacterRange::IsCanonical(ranges))
+                CharacterRange::Canonicalize(ranges);
+
+            // Now they are in order so we only need to look at the first.
+            int range_count = ranges.length();
+            if (cc->is_negated()) {
+                if (range_count != 0 &&
+                    ranges[0].from() == 0 &&
+                    ranges[0].to() >= kMaxOneByteCharCode)
+                {
+                    // This will be handled in a later filter.
+                    if (ignore_case && RangesContainLatin1Equivalents(ranges))
+                        continue;
+                    return set_replacement(nullptr);
+                }
+            } else {
+                if (range_count == 0 ||
+                    ranges[0].from() > kMaxOneByteCharCode)
+                {
+                    // This will be handled in a later filter.
+                    if (ignore_case && RangesContainLatin1Equivalents(ranges))
+                        continue;
+                    return set_replacement(nullptr);
+                }
+            }
+        }
+    }
+    return FilterSuccessor(depth - 1, ignore_case);
+}
+
+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()[i];
+        elm.set_cp_offset(cp_offset);
+        cp_offset += elm.length();
+    }
+}
+
+void TextNode::MakeCaseIndependent(bool is_ascii)
+{
+    int element_count = elements().length();
+    for (int i = 0; i < element_count; i++) {
+        TextElement elm = elements()[i];
+        if (elm.text_type() == TextElement::CHAR_CLASS) {
+            RegExpCharacterClass* cc = elm.char_class();
+
+            // None of the standard character classes is different in the case
+            // independent case and it slows us down if we don't know that.
+            if (cc->is_standard(alloc()))
+                continue;
+
+            CharacterRangeVector &ranges = cc->ranges(alloc());
+            int range_count = ranges.length();
+            for (int j = 0; j < range_count; j++)
+                ranges[j].AddCaseEquivalents(is_ascii, &ranges);
+        }
+    }
+}
+
+// -------------------------------------------------------------------
+// AssertionNode
+
+int
+AssertionNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start)
+{
+    if (budget <= 0)
+        return 0;
+
+    // If we know we are not at the start and we are asked "how many characters
+    // will you match if you succeed?" then we can answer anything since false
+    // implies false.  So lets just return the max answer (still_to_find) since
+    // that won't prevent us from preloading a lot of characters for the other
+    // branches in the node graph.
+    if (assertion_type() == AT_START && not_at_start)
+        return still_to_find;
+
+    return on_success()->EatsAtLeast(still_to_find, budget - 1, not_at_start);
+}
+
+void
+AssertionNode::FillInBMInfo(int offset, int budget, BoyerMooreLookahead* bm, bool not_at_start)
+{
+    // Match the behaviour of EatsAtLeast on this node.
+    if (assertion_type() == AT_START && not_at_start)
+        return;
+
+    on_success()->FillInBMInfo(offset, budget - 1, bm, not_at_start);
+    SaveBMInfo(bm, not_at_start, offset);
+}
+
+// -------------------------------------------------------------------
+// BackReferenceNode
+
+int
+BackReferenceNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start)
+{
+    if (budget <= 0)
+        return 0;
+    return on_success()->EatsAtLeast(still_to_find, budget - 1, not_at_start);
+}
+
+void
+BackReferenceNode::FillInBMInfo(int offset, int budget, BoyerMooreLookahead* bm, bool not_at_start)
+{
+    // Working out the set of characters that a backreference can match is too
+    // hard, so we just say that any character can match.
+    bm->SetRest(offset);
+    SaveBMInfo(bm, not_at_start, offset);
+}
+
+// -------------------------------------------------------------------
+// ChoiceNode
+
+int
+ChoiceNode::EatsAtLeastHelper(int still_to_find,
+                              int budget,
+                              RegExpNode* ignore_this_node,
+                              bool not_at_start)
+{
+    if (budget <= 0)
+        return 0;
+
+    int min = 100;
+    size_t choice_count = alternatives().length();
+    budget = (budget - 1) / choice_count;
+    for (size_t i = 0; i < choice_count; i++) {
+        RegExpNode* node = alternatives()[i].node();
+        if (node == ignore_this_node) continue;
+        int node_eats_at_least =
+            node->EatsAtLeast(still_to_find, budget, not_at_start);
+        if (node_eats_at_least < min)
+            min = node_eats_at_least;
+        if (min == 0)
+            return 0;
+    }
+    return min;
+}
+
+int
+ChoiceNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start)
+{
+    return EatsAtLeastHelper(still_to_find,
+                             budget,
+                             nullptr,
+                             not_at_start);
+}
+
+void
+ChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details,
+                                 RegExpCompiler* compiler,
+                                 int characters_filled_in,
+                                 bool not_at_start)
+{
+    not_at_start = (not_at_start || not_at_start_);
+    int choice_count = alternatives().length();
+    JS_ASSERT(choice_count > 0);
+    alternatives()[0].node()->GetQuickCheckDetails(details,
+                                                   compiler,
+                                                   characters_filled_in,
+                                                   not_at_start);
+    for (int i = 1; i < choice_count; i++) {
+        QuickCheckDetails new_details(details->characters());
+        RegExpNode* node = alternatives()[i].node();
+        node->GetQuickCheckDetails(&new_details, compiler,
+                                   characters_filled_in,
+                                   not_at_start);
+        // Here we merge the quick match details of the two branches.
+        details->Merge(&new_details, characters_filled_in);
+    }
+}
+
+void
+ChoiceNode::FillInBMInfo(int offset,
+                         int budget,
+                         BoyerMooreLookahead* bm,
+                         bool not_at_start)
+{
+    const GuardedAlternativeVector &alts = alternatives();
+    budget = (budget - 1) / alts.length();
+    for (size_t i = 0; i < alts.length(); i++) {
+        const GuardedAlternative& alt = alts[i];
+        if (alt.guards() != nullptr && alt.guards()->length() != 0) {
+            bm->SetRest(offset);  // Give up trying to fill in info.
+            SaveBMInfo(bm, not_at_start, offset);
+            return;
+        }
+        alt.node()->FillInBMInfo(offset, budget, bm, not_at_start);
+    }
+    SaveBMInfo(bm, not_at_start, offset);
+}
+
+RegExpNode*
+ChoiceNode::FilterASCII(int depth, bool ignore_case)
+{
+    if (info()->replacement_calculated)
+        return replacement();
+    if (depth < 0)
+        return this;
+    if (info()->visited)
+        return this;
+    VisitMarker marker(info());
+    int choice_count = alternatives().length();
+
+    for (int i = 0; i < choice_count; i++) {
+        const GuardedAlternative alternative = alternatives()[i];
+        if (alternative.guards() != nullptr && alternative.guards()->length() != 0) {
+            set_replacement(this);
+            return this;
+        }
+    }
+
+    int surviving = 0;
+    RegExpNode* survivor = nullptr;
+    for (int i = 0; i < choice_count; i++) {
+        GuardedAlternative alternative = alternatives()[i];
+        RegExpNode* replacement =
+            alternative.node()->FilterASCII(depth - 1, ignore_case);
+        JS_ASSERT(replacement != this);  // No missing EMPTY_MATCH_CHECK.
+        if (replacement != nullptr) {
+            alternatives()[i].set_node(replacement);
+            surviving++;
+            survivor = replacement;
+        }
+    }
+    if (surviving < 2)
+        return set_replacement(survivor);
+
+    set_replacement(this);
+    if (surviving == choice_count)
+        return this;
+
+    // Only some of the nodes survived the filtering.  We need to rebuild the
+    // alternatives list.
+    GuardedAlternativeVector new_alternatives(*alloc());
+    new_alternatives.reserve(surviving);
+    for (int i = 0; i < choice_count; i++) {
+        RegExpNode* replacement =
+            alternatives()[i].node()->FilterASCII(depth - 1, ignore_case);
+        if (replacement != nullptr) {
+            alternatives()[i].set_node(replacement);
+            new_alternatives.append(alternatives()[i]);
+        }
+    }
+
+    alternatives_.appendAll(new_alternatives);
+    return this;
+}
+
+// -------------------------------------------------------------------
+// NegativeLookaheadChoiceNode
+
+int
+NegativeLookaheadChoiceNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start)
+{
+    if (budget <= 0)
+        return 0;
+
+    // Alternative 0 is the negative lookahead, alternative 1 is what comes
+    // afterwards.
+    RegExpNode* node = alternatives()[1].node();
+    return node->EatsAtLeast(still_to_find, budget - 1, not_at_start);
+}
+
+void
+NegativeLookaheadChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details,
+                                                  RegExpCompiler* compiler,
+                                                  int filled_in,
+                                                  bool not_at_start)
+{
+    // Alternative 0 is the negative lookahead, alternative 1 is what comes
+    // afterwards.
+    RegExpNode* node = alternatives()[1].node();
+    return node->GetQuickCheckDetails(details, compiler, filled_in, not_at_start);
+}
+
+RegExpNode *
+NegativeLookaheadChoiceNode::FilterASCII(int depth, bool ignore_case)
+{
+    if (info()->replacement_calculated)
+        return replacement();
+    if (depth < 0)
+        return this;
+    if (info()->visited)
+        return this;
+
+    VisitMarker marker(info());
+
+    // Alternative 0 is the negative lookahead, alternative 1 is what comes
+    // afterwards.
+    RegExpNode* node = alternatives()[1].node();
+    RegExpNode* replacement = node->FilterASCII(depth - 1, ignore_case);
+
+    if (replacement == nullptr)
+        return set_replacement(nullptr);
+    alternatives()[1].set_node(replacement);
+
+    RegExpNode* neg_node = alternatives()[0].node();
+    RegExpNode* neg_replacement = neg_node->FilterASCII(depth - 1, ignore_case);
+
+    // If the negative lookahead is always going to fail then
+    // we don't need to check it.
+    if (neg_replacement == nullptr)
+        return set_replacement(replacement);
+
+    alternatives()[0].set_node(neg_replacement);
+    return set_replacement(this);
+}
+
+// -------------------------------------------------------------------
+// LoopChoiceNode
+
+void
+GuardedAlternative::AddGuard(LifoAlloc *alloc, Guard *guard)
+{
+    if (guards_ == nullptr)
+        guards_ = alloc->newInfallible<GuardVector>(*alloc);
+    guards_->append(guard);
+}
+
+void
+LoopChoiceNode::AddLoopAlternative(GuardedAlternative alt)
+{
+    JS_ASSERT(loop_node_ == nullptr);
+    AddAlternative(alt);
+    loop_node_ = alt.node();
+}
+
+
+void
+LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt)
+{
+    JS_ASSERT(continue_node_ == nullptr);
+    AddAlternative(alt);
+    continue_node_ = alt.node();
+}
+
+int
+LoopChoiceNode::EatsAtLeast(int still_to_find,  int budget, bool not_at_start)
+{
+    return EatsAtLeastHelper(still_to_find,
+                             budget - 1,
+                             loop_node_,
+                             not_at_start);
+}
+
+void
+LoopChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details,
+                                     RegExpCompiler* compiler,
+                                     int characters_filled_in,
+                                     bool not_at_start)
+{
+    if (body_can_be_zero_length_ || info()->visited)
+        return;
+    VisitMarker marker(info());
+    return ChoiceNode::GetQuickCheckDetails(details,
+                                            compiler,
+                                            characters_filled_in,
+                                            not_at_start);
+}
+
+void
+LoopChoiceNode::FillInBMInfo(int offset,
+                             int budget,
+                             BoyerMooreLookahead* bm,
+                             bool not_at_start)
+{
+    if (body_can_be_zero_length_ || budget <= 0) {
+        bm->SetRest(offset);
+        SaveBMInfo(bm, not_at_start, offset);
+        return;
+    }
+    ChoiceNode::FillInBMInfo(offset, budget - 1, bm, not_at_start);
+    SaveBMInfo(bm, not_at_start, offset);
+}
+
+RegExpNode *
+LoopChoiceNode::FilterASCII(int depth, bool ignore_case)
+{
+    if (info()->replacement_calculated)
+        return replacement();
+    if (depth < 0)
+        return this;
+    if (info()->visited)
+        return this;
+
+    {
+        VisitMarker marker(info());
+
+        RegExpNode* continue_replacement =
+            continue_node_->FilterASCII(depth - 1, ignore_case);
+
+        // If we can't continue after the loop then there is no sense in doing the
+        // loop.
+        if (continue_replacement == nullptr)
+            return set_replacement(nullptr);
+    }
+
+    return ChoiceNode::FilterASCII(depth - 1, ignore_case);
+}
+
+// -------------------------------------------------------------------
+// Analysis
+
+void
+Analysis::EnsureAnalyzed(RegExpNode* that)
+{
+    JS_CHECK_RECURSION(cx, fail("Stack overflow"); return);
+
+    if (that->info()->been_analyzed || that->info()->being_analyzed)
+        return;
+    that->info()->being_analyzed = true;
+    that->Accept(this);
+    that->info()->being_analyzed = false;
+    that->info()->been_analyzed = true;
+}
+
+void
+Analysis::VisitEnd(EndNode* that)
+{
+    // nothing to do
+}
+
+void
+Analysis::VisitText(TextNode* that)
+{
+    if (ignore_case_)
+        that->MakeCaseIndependent(is_ascii_);
+    EnsureAnalyzed(that->on_success());
+    if (!has_failed()) {
+        that->CalculateOffsets();
+    }
+}
+
+void
+Analysis::VisitAction(ActionNode* that)
+{
+    RegExpNode* target = that->on_success();
+    EnsureAnalyzed(target);
+
+    if (!has_failed()) {
+        // 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(target->info());
+    }
+}
+
+void
+Analysis::VisitChoice(ChoiceNode* that)
+{
+    NodeInfo* info = that->info();
+
+    for (size_t i = 0; i < that->alternatives().length(); i++) {
+        RegExpNode* node = that->alternatives()[i].node();
+        EnsureAnalyzed(node);
+        if (has_failed()) return;
+
+        // Anything the following nodes need to know has to be known by
+        // this node also, so it can pass it on.
+        info->AddFromFollowing(node->info());
+    }
+}
+
+void
+Analysis::VisitLoopChoice(LoopChoiceNode* that)
+{
+    NodeInfo* info = that->info();
+    for (size_t i = 0; i < that->alternatives().length(); i++) {
+        RegExpNode* node = that->alternatives()[i].node();
+        if (node != that->loop_node()) {
+            EnsureAnalyzed(node);
+            if (has_failed()) return;
+            info->AddFromFollowing(node->info());
+        }
+    }
+
+    // Check the loop last since it may need the value of this node
+    // to get a correct result.
+    EnsureAnalyzed(that->loop_node());
+    if (!has_failed())
+        info->AddFromFollowing(that->loop_node()->info());
+}
+
+void
+Analysis::VisitBackReference(BackReferenceNode* that)
+{
+    EnsureAnalyzed(that->on_success());
+}
+
+void
+Analysis::VisitAssertion(AssertionNode* that)
+{
+    EnsureAnalyzed(that->on_success());
+}
+
+// -------------------------------------------------------------------
+// Implementation 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 RegExpAST.cpp.
+//   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 Trace.  The Trace 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 Trace or update it.  Flushing the Trace
+//   will emit code to bring the actual state into line with the virtual state.
+//   Avoiding flushing the state can postpone some work (e.g. 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 Trace 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 trace is specialized
+//   to that trace.  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
+//   trace 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
+//   trace is not recorded in the node and so it cannot currently be reused in
+//   the event that code generation is requested for an identical trace.
+
+/* static */ TextElement
+TextElement::Atom(RegExpAtom* atom)
+{
+    return TextElement(ATOM, atom);
+}
+
+/* static */ TextElement
+TextElement::CharClass(RegExpCharacterClass* char_class)
+{
+    return TextElement(CHAR_CLASS, char_class);
+}
+
+int
+TextElement::length() const
+{
+    switch (text_type()) {
+      case ATOM:
+        return atom()->length();
+      case CHAR_CLASS:
+        return 1;
+    }
+    MOZ_ASSUME_UNREACHABLE("Bad text type");
+    return 0;
+}
+
+class FrequencyCollator
+{
+  public:
+    FrequencyCollator() : total_samples_(0) {
+        for (int i = 0; i < RegExpMacroAssembler::kTableSize; i++) {
+            frequencies_[i] = CharacterFrequency(i);
+        }
+    }
+
+    void CountCharacter(int character) {
+        int index = (character & RegExpMacroAssembler::kTableMask);
+        frequencies_[index].Increment();
+        total_samples_++;
+    }
+
+    // Does not measure in percent, but rather per-128 (the table size from the
+    // regexp macro assembler).
+    int Frequency(int in_character) {
+        JS_ASSERT((in_character & RegExpMacroAssembler::kTableMask) == in_character);
+        if (total_samples_ < 1) return 1;  // Division by zero.
+        int freq_in_per128 =
+            (frequencies_[in_character].counter() * 128) / total_samples_;
+        return freq_in_per128;
+    }
+
+  private:
+    class CharacterFrequency {
+      public:
+        CharacterFrequency() : counter_(0), character_(-1) { }
+        explicit CharacterFrequency(int character)
+          : counter_(0), character_(character)
+        {}
+
+        void Increment() { counter_++; }
+        int counter() { return counter_; }
+        int character() { return character_; }
+
+     private:
+        int counter_;
+        int character_;
+    };
+
+  private:
+    CharacterFrequency frequencies_[RegExpMacroAssembler::kTableSize];
+    int total_samples_;
+};
+
+class irregexp::RegExpCompiler
+{
+  public:
+    RegExpCompiler(LifoAlloc *alloc, int capture_count, bool ignore_case, bool is_ascii);
+
+    int AllocateRegister() {
+        if (next_register_ >= RegExpMacroAssembler::kMaxRegister) {
+            reg_exp_too_big_ = true;
+            return next_register_;
+        }
+        return next_register_++;
+    }
+
+    RegExpCode Assemble(JSContext *cx,
+                        RegExpMacroAssembler *assembler,
+                        RegExpNode *start,
+                        int capture_count);
+
+    inline void AddWork(RegExpNode* node) {
+        if (!work_list_.append(node))
+            CrashAtUnhandlableOOM("AddWork");
+    }
+
+    static const int kImplementationOffset = 0;
+    static const int kNumberOfRegistersOffset = 0;
+    static const int kCodeOffset = 1;
+
+    RegExpMacroAssembler* macro_assembler() { return macro_assembler_; }
+    EndNode* accept() { return accept_; }
+
+    static const int kMaxRecursion = 100;
+    inline int recursion_depth() { return recursion_depth_; }
+    inline void IncrementRecursionDepth() { recursion_depth_++; }
+    inline void DecrementRecursionDepth() { recursion_depth_--; }
+
+    void SetRegExpTooBig() { reg_exp_too_big_ = true; }
+
+    inline bool ignore_case() { return ignore_case_; }
+    inline bool ascii() { return ascii_; }
+    FrequencyCollator* frequency_collator() { return &frequency_collator_; }
+
+    int current_expansion_factor() { return current_expansion_factor_; }
+    void set_current_expansion_factor(int value) {
+        current_expansion_factor_ = value;
+    }
+
+    LifoAlloc *alloc() const { return alloc_; }
+
+    static const int kNoRegister = -1;
+
+  private:
+    EndNode* accept_;
+    int next_register_;
+    js::Vector<RegExpNode *, 4, SystemAllocPolicy> work_list_;
+    int recursion_depth_;
+    RegExpMacroAssembler* macro_assembler_;
+    bool ignore_case_;
+    bool ascii_;
+    bool reg_exp_too_big_;
+    int current_expansion_factor_;
+    FrequencyCollator frequency_collator_;
+    LifoAlloc *alloc_;
+};
+
+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(LifoAlloc *alloc, int capture_count, bool ignore_case, bool ascii)
+  : next_register_(2 * (capture_count + 1)),
+    recursion_depth_(0),
+    ignore_case_(ignore_case),
+    ascii_(ascii),
+    reg_exp_too_big_(false),
+    current_expansion_factor_(1),
+    frequency_collator_(),
+    alloc_(alloc)
+{
+    accept_ = alloc->newInfallible<EndNode>(alloc, EndNode::ACCEPT);
+    JS_ASSERT(next_register_ - 1 <= RegExpMacroAssembler::kMaxRegister);
+}
+
+RegExpCode
+RegExpCompiler::Assemble(JSContext *cx,
+                         RegExpMacroAssembler *assembler,
+                         RegExpNode *start,
+                         int capture_count)
+{
+    macro_assembler_ = assembler;
+    macro_assembler_->set_slow_safe(false);
+
+    jit::Label fail;
+    macro_assembler_->PushBacktrack(&fail);
+    Trace new_trace;
+    start->Emit(this, &new_trace);
+    macro_assembler_->BindBacktrack(&fail);
+    macro_assembler_->Fail();
+
+    while (!work_list_.empty())
+        work_list_.popCopy()->Emit(this, &new_trace);
+
+    RegExpCode code = macro_assembler_->GenerateCode(cx);
+    if (code.empty())
+        return RegExpCode();
+
+    if (reg_exp_too_big_) {
+        JS_ReportError(cx, "regexp too big");
+        code.destroy();
+        return RegExpCode();
+    }
+
+    return code;
+}
+
+RegExpCode
+irregexp::CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData *data,
+                         const jschar *sampleChars, size_t sampleLength,
+                         bool is_global, bool ignore_case, bool is_ascii)
+{
+    if ((data->capture_count + 1) * 2 - 1 > RegExpMacroAssembler::kMaxRegister) {
+        JS_ReportError(cx, "regexp too big");
+        return RegExpCode();
+    }
+
+    LifoAlloc &alloc = cx->tempLifoAlloc();
+    RegExpCompiler compiler(&alloc, data->capture_count, ignore_case, is_ascii);
+
+    // Sample some characters from the middle of the string.
+    static const int kSampleSize = 128;
+
+    int chars_sampled = 0;
+    int half_way = (sampleLength - kSampleSize) / 2;
+    for (size_t i = Max(0, half_way);
+         i < sampleLength && chars_sampled < kSampleSize;
+         i++, chars_sampled++)
+    {
+        compiler.frequency_collator()->CountCharacter(sampleChars[i]);
+    }
+
+    // Wrap the body of the regexp in capture #0.
+    RegExpNode* captured_body = RegExpCapture::ToNode(data->tree,
+                                                      0,
+                                                      &compiler,
+                                                      compiler.accept());
+    RegExpNode* node = captured_body;
+    bool is_end_anchored = data->tree->IsAnchoredAtEnd();
+    bool is_start_anchored = data->tree->IsAnchoredAtStart();
+    int max_length = data->tree->max_match();
+    if (!is_start_anchored) {
+        // Add a .*? at the beginning, outside the body capture, unless
+        // this expression is anchored at the beginning.
+        RegExpNode* loop_node =
+            RegExpQuantifier::ToNode(0,
+                                     RegExpTree::kInfinity,
+                                     false,
+                                     alloc.newInfallible<RegExpCharacterClass>('*'),
+                                     &compiler,
+                                     captured_body,
+                                     data->contains_anchor);
+
+        if (data->contains_anchor) {
+            // Unroll loop once, to take care of the case that might start
+            // at the start of input.
+            ChoiceNode *first_step_node = alloc.newInfallible<ChoiceNode>(&alloc, 2);
+            RegExpNode *char_class =
+                alloc.newInfallible<TextNode>(alloc.newInfallible<RegExpCharacterClass>('*'), loop_node);
+            first_step_node->AddAlternative(GuardedAlternative(captured_body));
+            first_step_node->AddAlternative(GuardedAlternative(char_class));
+            node = first_step_node;
+        } else {
+            node = loop_node;
+        }
+    }
+    if (is_ascii) {
+        node = node->FilterASCII(RegExpCompiler::kMaxRecursion, ignore_case);
+        // Do it again to propagate the new nodes to places where they were not
+        // put because they had not been calculated yet.
+        if (node != nullptr) {
+            node = node->FilterASCII(RegExpCompiler::kMaxRecursion, ignore_case);
+        }
+    }
+
+    if (node == nullptr)
+        node = alloc.newInfallible<EndNode>(&alloc, EndNode::BACKTRACK);
+
+    Analysis analysis(cx, ignore_case, is_ascii);
+    analysis.EnsureAnalyzed(node);
+    if (analysis.has_failed()) {
+        JS_ReportError(cx, analysis.errorMessage());
+        return RegExpCode();
+    }
+
+#ifdef JS_ION
+    Maybe<jit::IonContext> ctx;
+    Maybe<NativeRegExpMacroAssembler> native_assembler;
+    Maybe<InterpretedRegExpMacroAssembler> interpreted_assembler;
+
+    RegExpMacroAssembler *assembler;
+    if (cx->runtime()->options().nativeRegExp()) {
+        NativeRegExpMacroAssembler::Mode mode =
+            is_ascii ? NativeRegExpMacroAssembler::ASCII
+                     : NativeRegExpMacroAssembler::JSCHAR;
+
+        ctx.construct(cx, (jit::TempAllocator *) nullptr);
+        native_assembler.construct(&alloc, shared, cx->runtime(), mode, (data->capture_count + 1) * 2);
+        assembler = native_assembler.addr();
+    } else {
+        interpreted_assembler.construct(&alloc, shared, (data->capture_count + 1) * 2);
+        assembler = interpreted_assembler.addr();
+    }
+#else // JS_ION
+    InterpretedRegExpMacroAssembler macro_assembler(&alloc, shared, (data->capture_count + 1) * 2);
+    RegExpMacroAssembler *assembler = &macro_assembler;
+#endif // JS_ION
+
+    // Inserted here, instead of in Assembler, because it depends on information
+    // in the AST that isn't replicated in the Node structure.
+    static const int kMaxBacksearchLimit = 1024;
+    if (is_end_anchored &&
+        !is_start_anchored &&
+        max_length < kMaxBacksearchLimit) {
+        assembler->SetCurrentPositionFromEnd(max_length);
+    }
+
+    if (is_global) {
+        assembler->set_global_mode((data->tree->min_match() > 0)
+                                   ? RegExpMacroAssembler::GLOBAL_NO_ZERO_LENGTH_CHECK
+                                   : RegExpMacroAssembler::GLOBAL);
+    }
+
+    return compiler.Assemble(cx, assembler, node, data->capture_count);
+}
+
+RegExpRunStatus
+irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock,
+                      const jschar *chars, size_t start, size_t length, MatchPairs *matches)
+{
+#ifdef JS_ION
+    typedef void (*RegExpCodeSignature)(InputOutputData *);
+
+    InputOutputData data(chars, chars + length, start, matches);
+
+    RegExpCodeSignature function = reinterpret_cast<RegExpCodeSignature>(codeBlock->raw());
+    CALL_GENERATED_REGEXP(function, &data);
+
+    return (RegExpRunStatus) data.result;
+#else
+    MOZ_CRASH();
+#endif
+}
+
+// -------------------------------------------------------------------
+// Tree to graph conversion
+
+RegExpNode *
+RegExpAtom::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
+{
+    TextElementVector *elms =
+        compiler->alloc()->newInfallible<TextElementVector>(*compiler->alloc());
+    elms->append(TextElement::Atom(this));
+    return compiler->alloc()->newInfallible<TextNode>(elms, on_success);
+}
+
+RegExpNode *
+RegExpText::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
+{
+    return compiler->alloc()->newInfallible<TextNode>(&elements_, on_success);
+}
+
+RegExpNode *
+RegExpCharacterClass::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
+{
+    return compiler->alloc()->newInfallible<TextNode>(this, on_success);
+}
+
+RegExpNode *
+RegExpDisjunction::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
+{
+    const RegExpTreeVector &alternatives = this->alternatives();
+    size_t length = alternatives.length();
+    ChoiceNode* result = compiler->alloc()->newInfallible<ChoiceNode>(compiler->alloc(), length);
+    for (size_t i = 0; i < length; i++) {
+        GuardedAlternative alternative(alternatives[i]->ToNode(compiler, on_success));
+        result->AddAlternative(alternative);
+    }
+    return result;
+}
+
+RegExpNode *
+RegExpQuantifier::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
+{
+    return ToNode(min(),
+                  max(),
+                  is_greedy(),
+                  body(),
+                  compiler,
+                  on_success);
+}
+
+// Scoped object to keep track of how much we unroll quantifier loops in the
+// regexp graph generator.
+class RegExpExpansionLimiter
+{
+  public:
+    static const int kMaxExpansionFactor = 6;
+    RegExpExpansionLimiter(RegExpCompiler* compiler, int factor)
+      : compiler_(compiler),
+        saved_expansion_factor_(compiler->current_expansion_factor()),
+        ok_to_expand_(saved_expansion_factor_ <= kMaxExpansionFactor)
+    {
+        JS_ASSERT(factor > 0);
+        if (ok_to_expand_) {
+            if (factor > kMaxExpansionFactor) {
+                // Avoid integer overflow of the current expansion factor.
+                ok_to_expand_ = false;
+                compiler->set_current_expansion_factor(kMaxExpansionFactor + 1);
+            } else {
+                int new_factor = saved_expansion_factor_ * factor;
+                ok_to_expand_ = (new_factor <= kMaxExpansionFactor);
+                compiler->set_current_expansion_factor(new_factor);
+            }
+        }
+    }
+
+    ~RegExpExpansionLimiter() {
+        compiler_->set_current_expansion_factor(saved_expansion_factor_);
+    }
+
+    bool ok_to_expand() { return ok_to_expand_; }
+
+  private:
+    RegExpCompiler* compiler_;
+    int saved_expansion_factor_;
+    bool ok_to_expand_;
+};
+
+/* static */ RegExpNode *
+RegExpQuantifier::ToNode(int min,
+                         int max,
+                         bool is_greedy,
+                         RegExpTree* body,
+                         RegExpCompiler* compiler,
+                         RegExpNode* on_success,
+                         bool not_at_start /* = false */)
+{
+    // x{f, t} becomes this:
+    //
+    //             (r++)<-.
+    //               |     `
+    //               |     (x)
+    //               v     ^
+    //      (r=0)-->(?)---/ [if r < t]
+    //               |
+    //   [if r >= f] \----> ...
+    //
+
+    // 15.10.2.5 RepeatMatcher algorithm.
+    // The parser has already eliminated the case where max is 0.  In the case
+    // where max_match is zero the parser has removed the quantifier if min was
+    // > 0 and removed the atom if min was 0.  See AddQuantifierToAtom.
+
+    // If we know that we cannot match zero length then things are a little
+    // simpler since we don't need to make the special zero length match check
+    // from step 2.1.  If the min and max are small we can unroll a little in
+    // this case.
+    static const int kMaxUnrolledMinMatches = 3;  // Unroll (foo)+ and (foo){3,}
+    static const int kMaxUnrolledMaxMatches = 3;  // Unroll (foo)? and (foo){x,3}
+
+    if (max == 0)
+        return on_success;  // This can happen due to recursion.
+
+    bool body_can_be_empty = (body->min_match() == 0);
+    int body_start_reg = RegExpCompiler::kNoRegister;
+    Interval capture_registers = body->CaptureRegisters();
+    bool needs_capture_clearing = !capture_registers.is_empty();
+    LifoAlloc *alloc = compiler->alloc();
+
+    if (body_can_be_empty) {
+        body_start_reg = compiler->AllocateRegister();
+    } else if (!needs_capture_clearing) {
+        // Only unroll if there are no captures and the body can't be
+        // empty.
+        {
+            RegExpExpansionLimiter limiter(compiler, min + ((max != min) ? 1 : 0));
+            if (min > 0 && min <= kMaxUnrolledMinMatches && limiter.ok_to_expand()) {
+                int new_max = (max == kInfinity) ? max : max - min;
+                // Recurse once to get the loop or optional matches after the fixed
+                // ones.
+                RegExpNode* answer = ToNode(0, new_max, is_greedy, body, compiler, on_success, true);
+                // Unroll the forced matches from 0 to min.  This can cause chains of
+                // TextNodes (which the parser does not generate).  These should be
+                // combined if it turns out they hinder good code generation.
+                for (int i = 0; i < min; i++)
+                    answer = body->ToNode(compiler, answer);
+                return answer;
+            }
+        }
+        if (max <= kMaxUnrolledMaxMatches && min == 0) {
+            JS_ASSERT(max > 0);  // Due to the 'if' above.
+            RegExpExpansionLimiter limiter(compiler, max);
+            if (limiter.ok_to_expand()) {
+                // Unroll the optional matches up to max.
+                RegExpNode* answer = on_success;
+                for (int i = 0; i < max; i++) {
+                    ChoiceNode* alternation = alloc->newInfallible<ChoiceNode>(alloc, 2);
+                    if (is_greedy) {
+                        alternation->AddAlternative(GuardedAlternative(body->ToNode(compiler, answer)));
+                        alternation->AddAlternative(GuardedAlternative(on_success));
+                    } else {
+                        alternation->AddAlternative(GuardedAlternative(on_success));
+                        alternation->AddAlternative(GuardedAlternative(body->ToNode(compiler, answer)));
+                    }
+                    answer = alternation;
+                    if (not_at_start) alternation->set_not_at_start();
+                }
+                return answer;
+            }
+        }
+    }
+    bool has_min = min > 0;
+    bool has_max = max < RegExpTree::kInfinity;
+    bool needs_counter = has_min || has_max;
+    int reg_ctr = needs_counter
+        ? compiler->AllocateRegister()
+        : RegExpCompiler::kNoRegister;
+    LoopChoiceNode* center = alloc->newInfallible<LoopChoiceNode>(alloc, body->min_match() == 0);
+    if (not_at_start)
+        center->set_not_at_start();
+    RegExpNode* loop_return = needs_counter
+        ? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center))
+        : static_cast<RegExpNode*>(center);
+    if (body_can_be_empty) {
+        // If the body can be empty we need to check if it was and then
+        // backtrack.
+        loop_return = ActionNode::EmptyMatchCheck(body_start_reg,
+                                                  reg_ctr,
+                                                  min,
+                                                  loop_return);
+    }
+    RegExpNode* body_node = body->ToNode(compiler, loop_return);
+    if (body_can_be_empty) {
+        // If the body can be empty we need to store the start position
+        // so we can bail out if it was empty.
+        body_node = ActionNode::StorePosition(body_start_reg, false, body_node);
+    }
+    if (needs_capture_clearing) {
+        // Before entering the body of this loop we need to clear captures.
+        body_node = ActionNode::ClearCaptures(capture_registers, body_node);
+    }
+    GuardedAlternative body_alt(body_node);
+    if (has_max) {
+        Guard* body_guard = alloc->newInfallible<Guard>(reg_ctr, Guard::LT, max);
+        body_alt.AddGuard(alloc, body_guard);
+    }
+    GuardedAlternative rest_alt(on_success);
+    if (has_min) {
+        Guard* rest_guard = alloc->newInfallible<Guard>(reg_ctr, Guard::GEQ, min);
+        rest_alt.AddGuard(alloc, rest_guard);
+    }
+    if (is_greedy) {
+        center->AddLoopAlternative(body_alt);
+        center->AddContinueAlternative(rest_alt);
+    } else {
+        center->AddContinueAlternative(rest_alt);
+        center->AddLoopAlternative(body_alt);
+    }
+    if (needs_counter)
+        return ActionNode::SetRegister(reg_ctr, 0, center);
+    return center;
+}
+
+RegExpNode*
+RegExpAssertion::ToNode(RegExpCompiler* compiler,
+                        RegExpNode* on_success)
+{
+    NodeInfo info;
+    LifoAlloc *alloc = compiler->alloc();
+
+    switch (assertion_type()) {
+      case START_OF_LINE:
+        return AssertionNode::AfterNewline(on_success);
+      case START_OF_INPUT:
+        return AssertionNode::AtStart(on_success);
+      case BOUNDARY:
+        return AssertionNode::AtBoundary(on_success);
+      case NON_BOUNDARY:
+        return AssertionNode::AtNonBoundary(on_success);
+      case END_OF_INPUT:
+        return AssertionNode::AtEnd(on_success);
+      case END_OF_LINE: {
+        // Compile $ in multiline regexps as an alternation with a positive
+        // lookahead in one side and an end-of-input on the other side.
+        // We need two registers for the lookahead.
+        int stack_pointer_register = compiler->AllocateRegister();
+        int position_register = compiler->AllocateRegister();
+        // The ChoiceNode to distinguish between a newline and end-of-input.
+        ChoiceNode* result = alloc->newInfallible<ChoiceNode>(alloc, 2);
+        // Create a newline atom.
+        CharacterRangeVector *newline_ranges = alloc->newInfallible<CharacterRangeVector>(*alloc);
+        CharacterRange::AddClassEscape(alloc, 'n', newline_ranges);
+        RegExpCharacterClass* newline_atom = alloc->newInfallible<RegExpCharacterClass>('n');
+        TextNode* newline_matcher =
+            alloc->newInfallible<TextNode>(newline_atom,
+                ActionNode::PositiveSubmatchSuccess(stack_pointer_register,
+                                                    position_register,
+                                                    0,  // No captures inside.
+                                                    -1,  // Ignored if no captures.
+                                                    on_success));
+        // Create an end-of-input matcher.
+        RegExpNode* end_of_line =
+            ActionNode::BeginSubmatch(stack_pointer_register, position_register, newline_matcher);
+
+        // Add the two alternatives to the ChoiceNode.
+        GuardedAlternative eol_alternative(end_of_line);
+        result->AddAlternative(eol_alternative);
+        GuardedAlternative end_alternative(AssertionNode::AtEnd(on_success));
+        result->AddAlternative(end_alternative);
+        return result;
+      }
+      default:
+        MOZ_ASSUME_UNREACHABLE("Bad assertion type");
+    }
+    return on_success;
+}
+
+RegExpNode *
+RegExpBackReference::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
+{
+    return compiler->alloc()->newInfallible<BackReferenceNode>(RegExpCapture::StartRegister(index()),
+                                                               RegExpCapture::EndRegister(index()),
+                                                               on_success);
+}
+
+RegExpNode *
+RegExpEmpty::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
+{
+    return on_success;
+}
+
+RegExpNode *
+RegExpLookahead::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
+{
+    int stack_pointer_register = compiler->AllocateRegister();
+    int position_register = compiler->AllocateRegister();
+
+    const int registers_per_capture = 2;
+    const int register_of_first_capture = 2;
+    int register_count = capture_count_ * registers_per_capture;
+    int register_start =
+        register_of_first_capture + capture_from_ * registers_per_capture;
+
+    if (is_positive()) {
+        RegExpNode *bodyNode =
+            body()->ToNode(compiler,
+                           ActionNode::PositiveSubmatchSuccess(stack_pointer_register,
+                                                               position_register,
+                                                               register_count,
+                                                               register_start,
+                                                               on_success));
+        return ActionNode::BeginSubmatch(stack_pointer_register,
+                                         position_register,
+                                         bodyNode);
+    }
+
+    // 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.  The NegativeLookaheadChoiceNode is a special
+    // ChoiceNode that knows to ignore the first exit when calculating quick
+    // checks.
+    LifoAlloc *alloc = compiler->alloc();
+
+    RegExpNode *success =
+        alloc->newInfallible<NegativeSubmatchSuccess>(alloc,
+                                                      stack_pointer_register,
+                                                      position_register,
+                                                      register_count,
+                                                      register_start);
+    GuardedAlternative body_alt(body()->ToNode(compiler, success));
+
+    ChoiceNode *choice_node =
+        alloc->newInfallible<NegativeLookaheadChoiceNode>(alloc, body_alt, GuardedAlternative(on_success));
+
+    return ActionNode::BeginSubmatch(stack_pointer_register,
+                                     position_register,
+                                     choice_node);
+}
+
+RegExpNode *
+RegExpCapture::ToNode(RegExpCompiler *compiler, RegExpNode* on_success)
+{
+    return ToNode(body(), index(), compiler, on_success);
+}
+
+/* static */ RegExpNode *
+RegExpCapture::ToNode(RegExpTree* body,
+                      int index,
+                      RegExpCompiler* compiler,
+                      RegExpNode* on_success)
+{
+    int start_reg = RegExpCapture::StartRegister(index);
+    int end_reg = RegExpCapture::EndRegister(index);
+    RegExpNode* store_end = ActionNode::StorePosition(end_reg, true, on_success);
+    RegExpNode* body_node = body->ToNode(compiler, store_end);
+    return ActionNode::StorePosition(start_reg, true, body_node);
+}
+
+RegExpNode*
+RegExpAlternative::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
+{
+    const RegExpTreeVector &children = nodes();
+    RegExpNode *current = on_success;
+    for (int i = children.length() - 1; i >= 0; i--)
+        current = children[i]->ToNode(compiler, current);
+    return current;
+}
+
+// -------------------------------------------------------------------
+// BoyerMooreLookahead
+
+ContainedInLattice
+irregexp::AddRange(ContainedInLattice containment,
+                   const int* ranges,
+                   int ranges_length,
+                   Interval new_range)
+{
+    JS_ASSERT((ranges_length & 1) == 1);
+    JS_ASSERT(ranges[ranges_length - 1] == kMaxUtf16CodeUnit + 1);
+    if (containment == kLatticeUnknown) return containment;
+    bool inside = false;
+    int last = 0;
+    for (int i = 0; i < ranges_length; inside = !inside, last = ranges[i], i++) {
+        // Consider the range from last to ranges[i].
+        // We haven't got to the new range yet.
+        if (ranges[i] <= new_range.from())
+            continue;
+
+        // New range is wholly inside last-ranges[i].  Note that new_range.to() is
+        // inclusive, but the values in ranges are not.
+        if (last <= new_range.from() && new_range.to() < ranges[i])
+            return Combine(containment, inside ? kLatticeIn : kLatticeOut);
+
+        return kLatticeUnknown;
+    }
+    return containment;
+}
+
+void
+BoyerMoorePositionInfo::Set(int character)
+{
+    SetInterval(Interval(character, character));
+}
+
+void
+BoyerMoorePositionInfo::SetInterval(const Interval& interval)
+{
+    s_ = AddRange(s_, kSpaceRanges, kSpaceRangeCount, interval);
+    w_ = AddRange(w_, kWordRanges, kWordRangeCount, interval);
+    d_ = AddRange(d_, kDigitRanges, kDigitRangeCount, interval);
+    surrogate_ =
+        AddRange(surrogate_, kSurrogateRanges, kSurrogateRangeCount, interval);
+    if (interval.to() - interval.from() >= kMapSize - 1) {
+        if (map_count_ != kMapSize) {
+            map_count_ = kMapSize;
+            for (int i = 0; i < kMapSize; i++)
+                map_[i] = true;
+        }
+        return;
+    }
+    for (int i = interval.from(); i <= interval.to(); i++) {
+        int mod_character = (i & kMask);
+        if (!map_[mod_character]) {
+            map_count_++;
+            map_[mod_character] = true;
+        }
+        if (map_count_ == kMapSize)
+            return;
+    }
+}
+
+void
+BoyerMoorePositionInfo::SetAll()
+{
+    s_ = w_ = d_ = kLatticeUnknown;
+    if (map_count_ != kMapSize) {
+        map_count_ = kMapSize;
+        for (int i = 0; i < kMapSize; i++)
+            map_[i] = true;
+    }
+}
+
+BoyerMooreLookahead::BoyerMooreLookahead(LifoAlloc *alloc, size_t length, RegExpCompiler* compiler)
+  : length_(length), compiler_(compiler), bitmaps_(*alloc)
+{
+    max_char_ = MaximumCharacter(compiler->ascii());
+
+    bitmaps_.reserve(length);
+    for (size_t i = 0; i < length; i++)
+        bitmaps_.append(alloc->newInfallible<BoyerMoorePositionInfo>(alloc));
+}
+
+// Find the longest range of lookahead that has the fewest number of different
+// characters that can occur at a given position.  Since we are optimizing two
+// different parameters at once this is a tradeoff.
+bool BoyerMooreLookahead::FindWorthwhileInterval(int* from, int* to) {
+  int biggest_points = 0;
+  // If more than 32 characters out of 128 can occur it is unlikely that we can
+  // be lucky enough to step forwards much of the time.
+  const int kMaxMax = 32;
+  for (int max_number_of_chars = 4;
+       max_number_of_chars < kMaxMax;
+       max_number_of_chars *= 2) {
+    biggest_points =
+        FindBestInterval(max_number_of_chars, biggest_points, from, to);
+  }
+  if (biggest_points == 0) return false;
+  return true;
+}
+
+// Find the highest-points range between 0 and length_ where the character
+// information is not too vague.  'Too vague' means that there are more than
+// max_number_of_chars that can occur at this position.  Calculates the number
+// of points as the product of width-of-the-range and
+// probability-of-finding-one-of-the-characters, where the probability is
+// calculated using the frequency distribution of the sample subject string.
+int
+BoyerMooreLookahead::FindBestInterval(int max_number_of_chars, int old_biggest_points,
+                                      int* from, int* to)
+{
+    int biggest_points = old_biggest_points;
+    static const int kSize = RegExpMacroAssembler::kTableSize;
+    for (int i = 0; i < length_; ) {
+        while (i < length_ && Count(i) > max_number_of_chars) i++;
+        if (i == length_) break;
+        int remembered_from = i;
+        bool union_map[kSize];
+        for (int j = 0; j < kSize; j++) union_map[j] = false;
+        while (i < length_ && Count(i) <= max_number_of_chars) {
+            BoyerMoorePositionInfo* map = bitmaps_[i];
+            for (int j = 0; j < kSize; j++) union_map[j] |= map->at(j);
+            i++;
+        }
+        int frequency = 0;
+        for (int j = 0; j < kSize; j++) {
+            if (union_map[j]) {
+                // Add 1 to the frequency to give a small per-character boost for
+                // the cases where our sampling is not good enough and many
+                // characters have a frequency of zero.  This means the frequency
+                // can theoretically be up to 2*kSize though we treat it mostly as
+                // a fraction of kSize.
+                frequency += compiler_->frequency_collator()->Frequency(j) + 1;
+            }
+        }
+        // We use the probability of skipping times the distance we are skipping to
+        // judge the effectiveness of this.  Actually we have a cut-off:  By
+        // dividing by 2 we switch off the skipping if the probability of skipping
+        // is less than 50%.  This is because the multibyte mask-and-compare
+        // skipping in quickcheck is more likely to do well on this case.
+        bool in_quickcheck_range = ((i - remembered_from < 4) ||
+                                    (compiler_->ascii() ? remembered_from <= 4 : remembered_from <= 2));
+        // Called 'probability' but it is only a rough estimate and can actually
+        // be outside the 0-kSize range.
+        int probability = (in_quickcheck_range ? kSize / 2 : kSize) - frequency;
+        int points = (i - remembered_from) * probability;
+        if (points > biggest_points) {
+            *from = remembered_from;
+            *to = i - 1;
+            biggest_points = points;
+        }
+    }
+    return biggest_points;
+}
+
+// Take all the characters that will not prevent a successful match if they
+// occur in the subject string in the range between min_lookahead and
+// max_lookahead (inclusive) measured from the current position.  If the
+// character at max_lookahead offset is not one of these characters, then we
+// can safely skip forwards by the number of characters in the range.
+int BoyerMooreLookahead::GetSkipTable(int min_lookahead,
+                                      int max_lookahead,
+                                      uint8_t *boolean_skip_table)
+{
+    const int kSize = RegExpMacroAssembler::kTableSize;
+
+    const int kSkipArrayEntry = 0;
+    const int kDontSkipArrayEntry = 1;
+
+    for (int i = 0; i < kSize; i++)
+        boolean_skip_table[i] = kSkipArrayEntry;
+    int skip = max_lookahead + 1 - min_lookahead;
+
+    for (int i = max_lookahead; i >= min_lookahead; i--) {
+        BoyerMoorePositionInfo* map = bitmaps_[i];
+        for (int j = 0; j < kSize; j++) {
+            if (map->at(j))
+                boolean_skip_table[j] = kDontSkipArrayEntry;
+        }
+    }
+
+    return skip;
+}
+
+// See comment on the implementation of GetSkipTable.
+bool
+BoyerMooreLookahead::EmitSkipInstructions(RegExpMacroAssembler* masm)
+{
+    const int kSize = RegExpMacroAssembler::kTableSize;
+
+    int min_lookahead = 0;
+    int max_lookahead = 0;
+
+    if (!FindWorthwhileInterval(&min_lookahead, &max_lookahead))
+        return false;
+
+    bool found_single_character = false;
+    int single_character = 0;
+    for (int i = max_lookahead; i >= min_lookahead; i--) {
+        BoyerMoorePositionInfo* map = bitmaps_[i];
+        if (map->map_count() > 1 ||
+            (found_single_character && map->map_count() != 0)) {
+            found_single_character = false;
+            break;
+        }
+        for (int j = 0; j < kSize; j++) {
+            if (map->at(j)) {
+                found_single_character = true;
+                single_character = j;
+                break;
+            }
+        }
+    }
+
+    int lookahead_width = max_lookahead + 1 - min_lookahead;
+
+    if (found_single_character && lookahead_width == 1 && max_lookahead < 3) {
+        // The mask-compare can probably handle this better.
+        return false;
+    }
+
+    if (found_single_character) {
+        jit::Label cont, again;
+        masm->Bind(&again);
+        masm->LoadCurrentCharacter(max_lookahead, &cont, true);
+        if (max_char_ > kSize) {
+            masm->CheckCharacterAfterAnd(single_character,
+                                         RegExpMacroAssembler::kTableMask,
+                                         &cont);
+        } else {
+            masm->CheckCharacter(single_character, &cont);
+        }
+        masm->AdvanceCurrentPosition(lookahead_width);
+        masm->JumpOrBacktrack(&again);
+        masm->Bind(&cont);
+        return true;
+    }
+
+    uint8_t *boolean_skip_table = static_cast<uint8_t *>(js_malloc(kSize));
+    if (!boolean_skip_table || !masm->shared->addTable(boolean_skip_table))
+        CrashAtUnhandlableOOM("Table malloc");
+
+    int skip_distance = GetSkipTable(min_lookahead, max_lookahead, boolean_skip_table);
+    JS_ASSERT(skip_distance != 0);
+
+    jit::Label cont, again;
+    masm->Bind(&again);
+    masm->LoadCurrentCharacter(max_lookahead, &cont, true);
+    masm->CheckBitInTable(boolean_skip_table, &cont);
+    masm->AdvanceCurrentPosition(skip_distance);
+    masm->JumpOrBacktrack(&again);
+    masm->Bind(&cont);
+
+    return true;
+}
+
+// -------------------------------------------------------------------
+// Trace
+
+bool Trace::DeferredAction::Mentions(int that)
+{
+    if (action_type() == ActionNode::CLEAR_CAPTURES) {
+        Interval range = static_cast<DeferredClearCaptures*>(this)->range();
+        return range.Contains(that);
+    }
+    return reg() == that;
+}
+
+bool Trace::mentions_reg(int reg)
+{
+    for (DeferredAction* action = actions_; action != nullptr; action = action->next()) {
+        if (action->Mentions(reg))
+            return true;
+    }
+    return false;
+}
+
+bool
+Trace::GetStoredPosition(int reg, int* cp_offset)
+{
+    JS_ASSERT(0 == *cp_offset);
+    for (DeferredAction* action = actions_; action != nullptr; action = action->next()) {
+        if (action->Mentions(reg)) {
+            if (action->action_type() == ActionNode::STORE_POSITION) {
+                *cp_offset = static_cast<DeferredCapture*>(action)->cp_offset();
+                return true;
+            }
+            return false;
+        }
+    }
+    return false;
+}
+
+int
+Trace::FindAffectedRegisters(LifoAlloc *alloc, OutSet* affected_registers)
+{
+    int max_register = RegExpCompiler::kNoRegister;
+    for (DeferredAction* action = actions_; action != nullptr; action = action->next()) {
+        if (action->action_type() == ActionNode::CLEAR_CAPTURES) {
+            Interval range = static_cast<DeferredClearCaptures*>(action)->range();
+            for (int i = range.from(); i <= range.to(); i++)
+                affected_registers->Set(alloc, i);
+            if (range.to() > max_register) max_register = range.to();
+        } else {
+            affected_registers->Set(alloc, action->reg());
+            if (action->reg() > max_register) max_register = action->reg();
+        }
+    }
+    return max_register;
+}
+
+void
+Trace::RestoreAffectedRegisters(RegExpMacroAssembler* assembler,
+                                int max_register,
+                                OutSet& registers_to_pop,
+                                OutSet& registers_to_clear)
+{
+    for (int reg = max_register; reg >= 0; reg--) {
+        if (registers_to_pop.Get(reg)) assembler->PopRegister(reg);
+        else if (registers_to_clear.Get(reg)) {
+            int clear_to = reg;
+            while (reg > 0 && registers_to_clear.Get(reg - 1))
+                reg--;
+            assembler->ClearRegisters(reg, clear_to);
+        }
+    }
+}
+
+enum DeferredActionUndoType {
+    DEFER_IGNORE,
+    DEFER_RESTORE,
+    DEFER_CLEAR
+};
+
+void
+Trace::PerformDeferredActions(LifoAlloc *alloc,
+                              RegExpMacroAssembler* assembler,
+                              int max_register,
+                              OutSet& affected_registers,
+                              OutSet* registers_to_pop,
+                              OutSet* registers_to_clear)
+{
+    // The "+1" is to avoid a push_limit of zero if stack_limit_slack() is 1.
+    const int push_limit = (assembler->stack_limit_slack() + 1) / 2;
+
+    // Count pushes performed to force a stack limit check occasionally.
+    int pushes = 0;
+
+    for (int reg = 0; reg <= max_register; reg++) {
+        if (!affected_registers.Get(reg))
+            continue;
+
+        // The chronologically first deferred action in the trace
+        // is used to infer the action needed to restore a register
+        // to its previous state (or not, if it's safe to ignore it).
+        DeferredActionUndoType undo_action = DEFER_IGNORE;
+
+        int value = 0;
+        bool absolute = false;
+        bool clear = 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 != nullptr;
+             action = action->next()) {
+            if (action->Mentions(reg)) {
+                switch (action->action_type()) {
+                  case ActionNode::SET_REGISTER: {
+                    Trace::DeferredSetRegister* psr =
+                        static_cast<Trace::DeferredSetRegister*>(action);
+                    if (!absolute) {
+                        value += psr->value();
+                        absolute = true;
+                    }
+                    // SET_REGISTER is currently only used for newly introduced loop
+                    // counters. They can have a significant previous value if they
+                    // occour in a loop. TODO(lrn): Propagate this information, so
+                    // we can set undo_action to IGNORE if we know there is no value to
+                    // restore.
+                    undo_action = DEFER_RESTORE;
+                    JS_ASSERT(store_position == -1);
+                    JS_ASSERT(!clear);
+                    break;
+                  }
+                  case ActionNode::INCREMENT_REGISTER:
+                    if (!absolute) {
+                        value++;
+                    }
+                    JS_ASSERT(store_position == -1);
+                    JS_ASSERT(!clear);
+                    undo_action = DEFER_RESTORE;
+                    break;
+                  case ActionNode::STORE_POSITION: {
+                    Trace::DeferredCapture* pc =
+                        static_cast<Trace::DeferredCapture*>(action);
+                    if (!clear && store_position == -1) {
+                        store_position = pc->cp_offset();
+                    }
+
+                    // For captures we know that stores and clears alternate.
+                    // Other register, are never cleared, and if the occur
+                    // inside a loop, they might be assigned more than once.
+                    if (reg <= 1) {
+                        // Registers zero and one, aka "capture zero", is
+                        // always set correctly if we succeed. There is no
+                        // need to undo a setting on backtrack, because we
+                        // will set it again or fail.
+                        undo_action = DEFER_IGNORE;
+                    } else {
+                        undo_action = pc->is_capture() ? DEFER_CLEAR : DEFER_RESTORE;
+                    }
+                    JS_ASSERT(!absolute);
+                    JS_ASSERT(value == 0);
+                    break;
+                  }
+                  case ActionNode::CLEAR_CAPTURES: {
+                    // Since we're scanning in reverse order, if we've already
+                    // set the position we have to ignore historically earlier
+                    // clearing operations.
+                    if (store_position == -1) {
+                        clear = true;
+                    }
+                    undo_action = DEFER_RESTORE;
+                    JS_ASSERT(!absolute);
+                    JS_ASSERT(value == 0);
+                    break;
+                  }
+                  default:
+                    MOZ_ASSUME_UNREACHABLE("Bad action");
+                    break;
+                }
+            }
+        }
+        // Prepare for the undo-action (e.g., push if it's going to be popped).
+        if (undo_action == DEFER_RESTORE) {
+            pushes++;
+            RegExpMacroAssembler::StackCheckFlag stack_check =
+                RegExpMacroAssembler::kNoStackLimitCheck;
+            if (pushes == push_limit) {
+                stack_check = RegExpMacroAssembler::kCheckStackLimit;
+                pushes = 0;
+            }
+
+            assembler->PushRegister(reg, stack_check);
+            registers_to_pop->Set(alloc, reg);
+        } else if (undo_action == DEFER_CLEAR) {
+            registers_to_clear->Set(alloc, reg);
+        }
+        // Perform the chronologically last action (or accumulated increment)
+        // for the register.
+        if (store_position != -1) {
+            assembler->WriteCurrentPositionToRegister(reg, store_position);
+        } else if (clear) {
+            assembler->ClearRegisters(reg, reg);
+        } else if (absolute) {
+            assembler->SetRegister(reg, value);
+        } else if (value != 0) {
+            assembler->AdvanceRegister(reg, value);
+        }
+    }
+}
+
+// This is called as we come into a loop choice node and some other tricky
+// nodes.  It normalizes the state of the code generator to ensure we can
+// generate generic code.
+void Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor)
+{
+    RegExpMacroAssembler* assembler = compiler->macro_assembler();
+
+    JS_ASSERT(!is_trivial());
+
+    if (actions_ == nullptr && backtrack() == nullptr) {
+        // Here we just have some deferred cp advances to fix and we are back to
+        // a normal situation.  We may also have to forget some information gained
+        // through a quick check that was already performed.
+        if (cp_offset_ != 0) assembler->AdvanceCurrentPosition(cp_offset_);
+        // Create a new trivial state and generate the node with that.
+        Trace new_state;
+        successor->Emit(compiler, &new_state);
+        return;
+    }
+
+    // Generate deferred actions here along with code to undo them again.
+    OutSet affected_registers;
+
+    if (backtrack() != nullptr) {
+        // 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.
+        assembler->PushCurrentPosition();
+    }
+
+    int max_register = FindAffectedRegisters(compiler->alloc(), &affected_registers);
+    OutSet registers_to_pop;
+    OutSet registers_to_clear;
+    PerformDeferredActions(compiler->alloc(),
+                           assembler,
+                           max_register,
+                           affected_registers,
+                           &registers_to_pop,
+                           &registers_to_clear);
+    if (cp_offset_ != 0)
+        assembler->AdvanceCurrentPosition(cp_offset_);
+
+    // Create a new trivial state and generate the node with that.
+    jit::Label undo;
+    assembler->PushBacktrack(&undo);
+    Trace new_state;
+    successor->Emit(compiler, &new_state);
+
+    // On backtrack we need to restore state.
+    assembler->BindBacktrack(&undo);
+    RestoreAffectedRegisters(assembler,
+                             max_register,
+                             registers_to_pop,
+                             registers_to_clear);
+    if (backtrack() == nullptr) {
+        assembler->Backtrack();
+    } else {
+        assembler->PopCurrentPosition();
+        assembler->JumpOrBacktrack(backtrack());
+    }
+}
+
+void
+Trace::InvalidateCurrentCharacter()
+{
+    characters_preloaded_ = 0;
+}
+
+void
+Trace::AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler)
+{
+    JS_ASSERT(by > 0);
+    // We don't have an instruction for shifting the current character register
+    // down or for using a shifted value for anything so lets just forget that
+    // we preloaded any characters into it.
+    characters_preloaded_ = 0;
+    // Adjust the offsets of the quick check performed information.  This
+    // information is used to find out what we already determined about the
+    // characters by means of mask and compare.
+    quick_check_performed_.Advance(by, compiler->ascii());
+    cp_offset_ += by;
+    if (cp_offset_ > RegExpMacroAssembler::kMaxCPOffset) {
+        compiler->SetRegExpTooBig();
+        cp_offset_ = 0;
+    }
+    bound_checked_up_to_ = Max(0, bound_checked_up_to_ - by);
+}
+
+void
+OutSet::Set(LifoAlloc *alloc, unsigned value)
+{
+    if (value < kFirstLimit) {
+        first_ |= (1 << value);
+    } else {
+        if (remaining_ == nullptr)
+            remaining_ = alloc->newInfallible<RemainingVector>(*alloc);
+
+        for (size_t i = 0; i < remaining().length(); i++) {
+            if (remaining()[i] == value)
+                return;
+        }
+        remaining().append(value);
+    }
+}
+
+bool
+OutSet::Get(unsigned value)
+{
+    if (value < kFirstLimit)
+        return (first_ & (1 << value)) != 0;
+    if (remaining_ == nullptr)
+        return false;
+    for (size_t i = 0; i < remaining().length(); i++) {
+        if (remaining()[i] == value)
+            return true;
+    }
+    return false;
+}
+
+// -------------------------------------------------------------------
+// Graph emitting
+
+void
+NegativeSubmatchSuccess::Emit(RegExpCompiler* compiler, Trace* trace)
+{
+    RegExpMacroAssembler* assembler = compiler->macro_assembler();
+
+    // Omit flushing the trace. We discard the entire stack frame anyway.
+
+    if (!label()->bound()) {
+        // We are completely independent of the trace, since we ignore it,
+        // so this code can be used as the generic version.
+        assembler->Bind(label());
+    }
+
+    // Throw away everything on the backtrack stack since the start
+    // of the negative submatch and restore the character position.
+    assembler->ReadCurrentPositionFromRegister(current_position_register_);
+    assembler->ReadBacktrackStackPointerFromRegister(stack_pointer_register_);
+
+    if (clear_capture_count_ > 0) {
+        // Clear any captures that might have been performed during the success
+        // of the body of the negative look-ahead.
+        int clear_capture_end = clear_capture_start_ + clear_capture_count_ - 1;
+        assembler->ClearRegisters(clear_capture_start_, clear_capture_end);
+    }
+
+    // Now that we have unwound the stack we find at the top of the stack the
+    // backtrack that the BeginSubmatch node got.
+    assembler->Backtrack();
+}
+
+void
+EndNode::Emit(RegExpCompiler* compiler, Trace* trace)
+{
+    if (!trace->is_trivial()) {
+        trace->Flush(compiler, this);
+        return;
+    }
+    RegExpMacroAssembler* assembler = compiler->macro_assembler();
+    if (!label()->bound()) {
+        assembler->Bind(label());
+    }
+    switch (action_) {
+    case ACCEPT:
+        assembler->Succeed();
+        return;
+    case BACKTRACK:
+        assembler->JumpOrBacktrack(trace->backtrack());
+        return;
+    case NEGATIVE_SUBMATCH_SUCCESS:
+        // This case is handled in a different virtual method.
+        MOZ_ASSUME_UNREACHABLE("Bad action");
+    }
+    MOZ_ASSUME_UNREACHABLE("Bad action");
+}
+
+// Emit the code to check for a ^ in multiline mode (1-character lookbehind
+// that matches newline or the start of input).
+static void
+EmitHat(RegExpCompiler* compiler, RegExpNode* on_success, Trace* trace)
+{
+    RegExpMacroAssembler* assembler = compiler->macro_assembler();
+
+    // We will be loading the previous character into the current character
+    // register.
+    Trace new_trace(*trace);
+    new_trace.InvalidateCurrentCharacter();
+
+    jit::Label ok;
+    if (new_trace.cp_offset() == 0) {
+        // The start of input counts as a newline in this context, so skip to
+        // ok if we are at the start.
+        assembler->CheckAtStart(&ok);
+    }
+
+    // We already checked that we are not at the start of input so it must be
+    // OK to load the previous character.
+    assembler->LoadCurrentCharacter(new_trace.cp_offset() -1, new_trace.backtrack(), false);
+
+    if (!assembler->CheckSpecialCharacterClass('n', new_trace.backtrack())) {
+        // Newline means \n, \r, 0x2028 or 0x2029.
+        if (!compiler->ascii())
+            assembler->CheckCharacterAfterAnd(0x2028, 0xfffe, &ok);
+        assembler->CheckCharacter('\n', &ok);
+        assembler->CheckNotCharacter('\r', new_trace.backtrack());
+    }
+    assembler->Bind(&ok);
+    on_success->Emit(compiler, &new_trace);
+}
+
+// Check for [0-9A-Z_a-z].
+static void
+EmitWordCheck(RegExpMacroAssembler* assembler,
+              jit::Label* word, jit::Label* non_word, bool fall_through_on_word)
+{
+    if (assembler->CheckSpecialCharacterClass(fall_through_on_word ? 'w' : 'W',
+                                              fall_through_on_word ? non_word : word))
+    {
+        // Optimized implementation available.
+        return;
+    }
+
+    assembler->CheckCharacterGT('z', non_word);
+    assembler->CheckCharacterLT('0', non_word);
+    assembler->CheckCharacterGT('a' - 1, word);
+    assembler->CheckCharacterLT('9' + 1, word);
+    assembler->CheckCharacterLT('A', non_word);
+    assembler->CheckCharacterLT('Z' + 1, word);
+
+    if (fall_through_on_word)
+        assembler->CheckNotCharacter('_', non_word);
+    else
+        assembler->CheckCharacter('_', word);
+}
+
+// Emit the code to handle \b and \B (word-boundary or non-word-boundary).
+void
+AssertionNode::EmitBoundaryCheck(RegExpCompiler* compiler, Trace* trace)
+{
+    RegExpMacroAssembler* assembler = compiler->macro_assembler();
+    Trace::TriBool next_is_word_character = Trace::UNKNOWN;
+    bool not_at_start = (trace->at_start() == Trace::FALSE_VALUE);
+    BoyerMooreLookahead* lookahead = bm_info(not_at_start);
+    if (lookahead == nullptr) {
+        int eats_at_least =
+            Min(kMaxLookaheadForBoyerMoore, EatsAtLeast(kMaxLookaheadForBoyerMoore,
+                                                        kRecursionBudget,
+                                                        not_at_start));
+        if (eats_at_least >= 1) {
+            BoyerMooreLookahead* bm =
+                alloc()->newInfallible<BoyerMooreLookahead>(alloc(), eats_at_least, compiler);
+            FillInBMInfo(0, kRecursionBudget, bm, not_at_start);
+            if (bm->at(0)->is_non_word())
+                next_is_word_character = Trace::FALSE_VALUE;
+            if (bm->at(0)->is_word()) next_is_word_character = Trace::TRUE_VALUE;
+        }
+    } else {
+        if (lookahead->at(0)->is_non_word())
+            next_is_word_character = Trace::FALSE_VALUE;
+        if (lookahead->at(0)->is_word())
+            next_is_word_character = Trace::TRUE_VALUE;
+    }
+    bool at_boundary = (assertion_type_ == AssertionNode::AT_BOUNDARY);
+    if (next_is_word_character == Trace::UNKNOWN) {
+        jit::Label before_non_word;
+        jit::Label before_word;
+        if (trace->characters_preloaded() != 1) {
+            assembler->LoadCurrentCharacter(trace->cp_offset(), &before_non_word);
+        }
+        // Fall through on non-word.
+        EmitWordCheck(assembler, &before_word, &before_non_word, false);
+        // Next character is not a word character.
+        assembler->Bind(&before_non_word);
+        jit::Label ok;
+        BacktrackIfPrevious(compiler, trace, at_boundary ? kIsNonWord : kIsWord);
+        assembler->JumpOrBacktrack(&ok);
+
+        assembler->Bind(&before_word);
+        BacktrackIfPrevious(compiler, trace, at_boundary ? kIsWord : kIsNonWord);
+        assembler->Bind(&ok);
+    } else if (next_is_word_character == Trace::TRUE_VALUE) {
+        BacktrackIfPrevious(compiler, trace, at_boundary ? kIsWord : kIsNonWord);
+    } else {
+        JS_ASSERT(next_is_word_character == Trace::FALSE_VALUE);
+        BacktrackIfPrevious(compiler, trace, at_boundary ? kIsNonWord : kIsWord);
+    }
+}
+
+void
+AssertionNode::BacktrackIfPrevious(RegExpCompiler* compiler,
+                                   Trace* trace,
+                                   AssertionNode::IfPrevious backtrack_if_previous)
+{
+    RegExpMacroAssembler* assembler = compiler->macro_assembler();
+    Trace new_trace(*trace);
+    new_trace.InvalidateCurrentCharacter();
+
+    jit::Label fall_through, dummy;
+
+    jit::Label* non_word = backtrack_if_previous == kIsNonWord ? new_trace.backtrack() : &fall_through;
+    jit::Label* word     = backtrack_if_previous == kIsNonWord ? &fall_through : new_trace.backtrack();
+
+    if (new_trace.cp_offset() == 0) {
+        // The start of input counts as a non-word character, so the question is
+        // decided if we are at the start.
+        assembler->CheckAtStart(non_word);
+    }
+    // We already checked that we are not at the start of input so it must be
+    // OK to load the previous character.
+    assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1, &dummy, false);
+    EmitWordCheck(assembler, word, non_word, backtrack_if_previous == kIsNonWord);
+
+    assembler->Bind(&fall_through);
+    on_success()->Emit(compiler, &new_trace);
+}
+
+void
+AssertionNode::GetQuickCheckDetails(QuickCheckDetails* details,
+                                    RegExpCompiler* compiler,
+                                    int filled_in,
+                                    bool not_at_start)
+{
+    if (assertion_type_ == AT_START && not_at_start) {
+        details->set_cannot_match();
+        return;
+    }
+    return on_success()->GetQuickCheckDetails(details, compiler, filled_in, not_at_start);
+}
+
+void
+AssertionNode::Emit(RegExpCompiler* compiler, Trace* trace)
+{
+    RegExpMacroAssembler* assembler = compiler->macro_assembler();
+    switch (assertion_type_) {
+      case AT_END: {
+        jit::Label ok;
+        assembler->CheckPosition(trace->cp_offset(), &ok);
+        assembler->JumpOrBacktrack(trace->backtrack());
+        assembler->Bind(&ok);
+        break;
+      }
+      case AT_START: {
+        if (trace->at_start() == Trace::FALSE_VALUE) {
+            assembler->JumpOrBacktrack(trace->backtrack());
+            return;
+        }
+        if (trace->at_start() == Trace::UNKNOWN) {
+            assembler->CheckNotAtStart(trace->backtrack());
+            Trace at_start_trace = *trace;
+            at_start_trace.set_at_start(true);
+            on_success()->Emit(compiler, &at_start_trace);
+            return;
+        }
+      }
+        break;
+      case AFTER_NEWLINE:
+        EmitHat(compiler, on_success(), trace);
+        return;
+      case AT_BOUNDARY:
+      case AT_NON_BOUNDARY: {
+        EmitBoundaryCheck(compiler, trace);
+        return;
+      }
+    }
+    on_success()->Emit(compiler, trace);
+}
+
+static bool
+DeterminedAlready(QuickCheckDetails* quick_check, int offset)
+{
+    if (quick_check == nullptr)
+        return false;
+    if (offset >= quick_check->characters())
+        return false;
+    return quick_check->positions(offset)->determines_perfectly;
+}
+
+static void
+UpdateBoundsCheck(int index, int* checked_up_to)
+{
+    if (index > *checked_up_to)
+        *checked_up_to = index;
+}
+
+static void
+EmitBoundaryTest(RegExpMacroAssembler* masm,
+                 int border,
+                 jit::Label* fall_through,
+                 jit::Label* above_or_equal,
+                 jit::Label* below)
+{
+    if (below != fall_through) {
+        masm->CheckCharacterLT(border, below);
+        if (above_or_equal != fall_through)
+            masm->JumpOrBacktrack(above_or_equal);
+    } else {
+        masm->CheckCharacterGT(border - 1, above_or_equal);
+    }
+}
+
+static void
+EmitDoubleBoundaryTest(RegExpMacroAssembler* masm,
+                       int first,
+                       int last,
+                       jit::Label* fall_through,
+                       jit::Label* in_range,
+                       jit::Label* out_of_range)
+{
+    if (in_range == fall_through) {
+        if (first == last)
+            masm->CheckNotCharacter(first, out_of_range);
+        else
+            masm->CheckCharacterNotInRange(first, last, out_of_range);
+    } else {
+        if (first == last)
+            masm->CheckCharacter(first, in_range);
+        else
+            masm->CheckCharacterInRange(first, last, in_range);
+        if (out_of_range != fall_through)
+            masm->JumpOrBacktrack(out_of_range);
+    }
+}
+
+typedef js::Vector<int, 4, LifoAllocPolicy<Infallible> > RangeBoundaryVector;
+
+// even_label is for ranges[i] to ranges[i + 1] where i - start_index is even.
+// odd_label is for ranges[i] to ranges[i + 1] where i - start_index is odd.
+static void
+EmitUseLookupTable(RegExpMacroAssembler* masm,
+                   RangeBoundaryVector &ranges,
+                   int start_index,
+                   int end_index,
+                   int min_char,
+                   jit::Label* fall_through,
+                   jit::Label* even_label,
+                   jit::Label* odd_label)
+{
+    static const int kSize = RegExpMacroAssembler::kTableSize;
+    static const int kMask = RegExpMacroAssembler::kTableMask;
+
+    DebugOnly<int> base = (min_char & ~kMask);
+
+    // Assert that everything is on one kTableSize page.
+    for (int i = start_index; i <= end_index; i++)
+        JS_ASSERT((ranges[i] & ~kMask) == base);
+    JS_ASSERT(start_index == 0 || (ranges[start_index - 1] & ~kMask) <= base);
+
+    char templ[kSize];
+    jit::Label* on_bit_set;
+    jit::Label* on_bit_clear;
+    int bit;
+    if (even_label == fall_through) {
+        on_bit_set = odd_label;
+        on_bit_clear = even_label;
+        bit = 1;
+    } else {
+        on_bit_set = even_label;
+        on_bit_clear = odd_label;
+        bit = 0;
+    }
+    for (int i = 0; i < (ranges[start_index] & kMask) && i < kSize; i++)
+        templ[i] = bit;
+    int j = 0;
+    bit ^= 1;
+    for (int i = start_index; i < end_index; i++) {
+        for (j = (ranges[i] & kMask); j < (ranges[i + 1] & kMask); j++) {
+            templ[j] = bit;
+        }
+        bit ^= 1;
+    }
+    for (int i = j; i < kSize; i++) {
+        templ[i] = bit;
+    }
+
+    // TODO(erikcorry): Cache these.
+    uint8_t *ba = static_cast<uint8_t *>(js_malloc(kSize));
+    if (!ba || !masm->shared->addTable(ba))
+        CrashAtUnhandlableOOM("Table malloc");
+
+    for (int i = 0; i < kSize; i++)
+        ba[i] = templ[i];
+
+    masm->CheckBitInTable(ba, on_bit_set);
+    if (on_bit_clear != fall_through)
+        masm->JumpOrBacktrack(on_bit_clear);
+}
+
+static void
+CutOutRange(RegExpMacroAssembler* masm,
+            RangeBoundaryVector &ranges,
+            int start_index,
+            int end_index,
+            int cut_index,
+            jit::Label* even_label,
+            jit::Label* odd_label)
+{
+    bool odd = (((cut_index - start_index) & 1) == 1);
+    jit::Label* in_range_label = odd ? odd_label : even_label;
+    jit::Label dummy;
+    EmitDoubleBoundaryTest(masm,
+                           ranges[cut_index],
+                           ranges[cut_index + 1] - 1,
+                           &dummy,
+                           in_range_label,
+                           &dummy);
+    JS_ASSERT(!dummy.used());
+    // Cut out the single range by rewriting the array.  This creates a new
+    // range that is a merger of the two ranges on either side of the one we
+    // are cutting out.  The oddity of the labels is preserved.
+    for (int j = cut_index; j > start_index; j--)
+        ranges[j] = ranges[j - 1];
+    for (int j = cut_index + 1; j < end_index; j++)
+        ranges[j] = ranges[j + 1];
+}
+
+// Unicode case.  Split the search space into kSize spaces that are handled
+// with recursion.
+static void
+SplitSearchSpace(RangeBoundaryVector &ranges,
+                 int start_index,
+                 int end_index,
+                 int* new_start_index,
+                 int* new_end_index,
+                 int* border)
+{
+    static const int kSize = RegExpMacroAssembler::kTableSize;
+    static const int kMask = RegExpMacroAssembler::kTableMask;
+
+    int first = ranges[start_index];
+    int last = ranges[end_index] - 1;
+
+    *new_start_index = start_index;
+    *border = (ranges[start_index] & ~kMask) + kSize;
+    while (*new_start_index < end_index) {
+        if (ranges[*new_start_index] > *border)
+            break;
+        (*new_start_index)++;
+    }
+    // new_start_index is the index of the first edge that is beyond the
+    // current kSize space.
+
+    // For very large search spaces we do a binary chop search of the non-ASCII
+    // space instead of just going to the end of the current kSize space.  The
+    // heuristics are complicated a little by the fact that any 128-character
+    // encoding space can be quickly tested with a table lookup, so we don't
+    // wish to do binary chop search at a smaller granularity than that.  A
+    // 128-character space can take up a lot of space in the ranges array if,
+    // for example, we only want to match every second character (eg. the lower
+    // case characters on some Unicode pages).
+    int binary_chop_index = (end_index + start_index) / 2;
+    // The first test ensures that we get to the code that handles the ASCII
+    // range with a single not-taken branch, speeding up this important
+    // character range (even non-ASCII charset-based text has spaces and
+    // punctuation).
+    if (*border - 1 > (int) kMaxOneByteCharCode &&  // ASCII case.
+        end_index - start_index > (*new_start_index - start_index) * 2 &&
+        last - first > kSize * 2 &&
+        binary_chop_index > *new_start_index &&
+        ranges[binary_chop_index] >= first + 2 * kSize)
+    {
+        int scan_forward_for_section_border = binary_chop_index;;
+        int new_border = (ranges[binary_chop_index] | kMask) + 1;
+
+        while (scan_forward_for_section_border < end_index) {
+            if (ranges[scan_forward_for_section_border] > new_border) {
+                *new_start_index = scan_forward_for_section_border;
+                *border = new_border;
+                break;
+            }
+            scan_forward_for_section_border++;
+        }
+    }
+
+    JS_ASSERT(*new_start_index > start_index);
+    *new_end_index = *new_start_index - 1;
+    if (ranges[*new_end_index] == *border)
+        (*new_end_index)--;
+    if (*border >= ranges[end_index]) {
+        *border = ranges[end_index];
+        *new_start_index = end_index;  // Won't be used.
+        *new_end_index = end_index - 1;
+    }
+}
+
+// Gets a series of segment boundaries representing a character class.  If the
+// character is in the range between an even and an odd boundary (counting from
+// start_index) then go to even_label, otherwise go to odd_label.  We already
+// know that the character is in the range of min_char to max_char inclusive.
+// Either label can be nullptr indicating backtracking.  Either label can also be
+// equal to the fall_through label.
+static void
+GenerateBranches(RegExpMacroAssembler* masm,
+                 RangeBoundaryVector &ranges,
+                 int start_index,
+                 int end_index,
+                 jschar min_char,
+                 jschar max_char,
+                 jit::Label* fall_through,
+                 jit::Label* even_label,
+                 jit::Label* odd_label)
+{
+    int first = ranges[start_index];
+    int last = ranges[end_index] - 1;
+
+    JS_ASSERT(min_char < first);
+
+    // Just need to test if the character is before or on-or-after
+    // a particular character.
+    if (start_index == end_index) {
+        EmitBoundaryTest(masm, first, fall_through, even_label, odd_label);
+        return;
+    }
+
+    // Another almost trivial case:  There is one interval in the middle that is
+    // different from the end intervals.
+    if (start_index + 1 == end_index) {
+        EmitDoubleBoundaryTest(masm, first, last, fall_through, even_label, odd_label);
+        return;
+    }
+
+    // It's not worth using table lookup if there are very few intervals in the
+    // character class.
+    if (end_index - start_index <= 6) {
+        // It is faster to test for individual characters, so we look for those
+        // first, then try arbitrary ranges in the second round.
+        static int kNoCutIndex = -1;
+        int cut = kNoCutIndex;
+        for (int i = start_index; i < end_index; i++) {
+            if (ranges[i] == ranges[i + 1] - 1) {
+                cut = i;
+                break;
+            }
+        }
+        if (cut == kNoCutIndex) cut = start_index;
+        CutOutRange(masm, ranges, start_index, end_index, cut, even_label, odd_label);
+        JS_ASSERT(end_index - start_index >= 2);
+        GenerateBranches(masm,
+                         ranges,
+                         start_index + 1,
+                         end_index - 1,
+                         min_char,
+                         max_char,
+                         fall_through,
+                         even_label,
+                         odd_label);
+        return;
+    }
+
+    // If there are a lot of intervals in the regexp, then we will use tables to
+    // determine whether the character is inside or outside the character class.
+    static const int kBits = RegExpMacroAssembler::kTableSizeBits;
+
+    if ((max_char >> kBits) == (min_char >> kBits)) {
+        EmitUseLookupTable(masm,
+                           ranges,
+                           start_index,
+                           end_index,
+                           min_char,
+                           fall_through,
+                           even_label,
+                           odd_label);
+        return;
+    }
+
+    if ((min_char >> kBits) != (first >> kBits)) {
+        masm->CheckCharacterLT(first, odd_label);
+        GenerateBranches(masm,
+                         ranges,
+                         start_index + 1,
+                         end_index,
+                         first,
+                         max_char,
+                         fall_through,
+                         odd_label,
+                         even_label);
+        return;
+    }
+
+    int new_start_index = 0;
+    int new_end_index = 0;
+    int border = 0;
+
+    SplitSearchSpace(ranges,
+                     start_index,
+                     end_index,
+                     &new_start_index,
+                     &new_end_index,
+                     &border);
+
+    jit::Label handle_rest;
+    jit::Label* above = &handle_rest;
+    if (border == last + 1) {
+        // We didn't find any section that started after the limit, so everything
+        // above the border is one of the terminal labels.
+        above = (end_index & 1) != (start_index & 1) ? odd_label : even_label;
+        JS_ASSERT(new_end_index == end_index - 1);
+    }
+
+    JS_ASSERT(start_index <= new_end_index);
+    JS_ASSERT(new_start_index <= end_index);
+    JS_ASSERT(start_index < new_start_index);
+    JS_ASSERT(new_end_index < end_index);
+    JS_ASSERT(new_end_index + 1 == new_start_index ||
+              (new_end_index + 2 == new_start_index &&
+               border == ranges[new_end_index + 1]));
+    JS_ASSERT(min_char < border - 1);
+    JS_ASSERT(border < max_char);
+    JS_ASSERT(ranges[new_end_index] < border);
+    JS_ASSERT(border < ranges[new_start_index] ||
+              (border == ranges[new_start_index] &&
+               new_start_index == end_index &&
+               new_end_index == end_index - 1 &&
+               border == last + 1));
+    JS_ASSERT(new_start_index == 0 || border >= ranges[new_start_index - 1]);
+
+    masm->CheckCharacterGT(border - 1, above);
+    jit::Label dummy;
+    GenerateBranches(masm,
+                     ranges,
+                     start_index,
+                     new_end_index,
+                     min_char,
+                     border - 1,
+                     &dummy,
+                     even_label,
+                     odd_label);
+    if (handle_rest.used()) {
+        masm->Bind(&handle_rest);
+        bool flip = (new_start_index & 1) != (start_index & 1);
+        GenerateBranches(masm,
+                         ranges,
+                         new_start_index,
+                         end_index,
+                         border,
+                         max_char,
+                         &dummy,
+                         flip ? odd_label : even_label,
+                         flip ? even_label : odd_label);
+    }
+}
+
+static void
+EmitCharClass(LifoAlloc *alloc,
+              RegExpMacroAssembler* macro_assembler,
+              RegExpCharacterClass* cc,
+              bool ascii,
+              jit::Label* on_failure,
+              int cp_offset,
+              bool check_offset,
+              bool preloaded)
+{
+    CharacterRangeVector &ranges = cc->ranges(alloc);
+    if (!CharacterRange::IsCanonical(ranges)) {
+        CharacterRange::Canonicalize(ranges);
+    }
+
+    int max_char = MaximumCharacter(ascii);
+    int range_count = ranges.length();
+
+    int last_valid_range = range_count - 1;
+    while (last_valid_range >= 0) {
+        CharacterRange& range = ranges[last_valid_range];
+        if (range.from() <= max_char) {
+            break;
+        }
+        last_valid_range--;
+    }
+
+    if (last_valid_range < 0) {
+        if (!cc->is_negated()) {
+            macro_assembler->JumpOrBacktrack(on_failure);
+        }
+        if (check_offset) {
+            macro_assembler->CheckPosition(cp_offset, on_failure);
+        }
+        return;
+    }
+
+    if (last_valid_range == 0 &&
+        ranges[0].IsEverything(max_char)) {
+        if (cc->is_negated()) {
+            macro_assembler->JumpOrBacktrack(on_failure);
+        } else {
+            // This is a common case hit by non-anchored expressions.
+            if (check_offset) {
+                macro_assembler->CheckPosition(cp_offset, on_failure);
+            }
+        }
+        return;
+    }
+    if (last_valid_range == 0 &&
+        !cc->is_negated() &&
+        ranges[0].IsEverything(max_char)) {
+        // This is a common case hit by non-anchored expressions.
+        if (check_offset) {
+            macro_assembler->CheckPosition(cp_offset, on_failure);
+        }
+        return;
+    }
+
+    if (!preloaded) {
+        macro_assembler->LoadCurrentCharacter(cp_offset, on_failure, check_offset);
+    }
+
+    if (cc->is_standard(alloc) &&
+        macro_assembler->CheckSpecialCharacterClass(cc->standard_type(),
+                                                    on_failure)) {
+        return;
+    }
+
+    // A new list with ascending entries.  Each entry is a code unit
+    // where there is a boundary between code units that are part of
+    // the class and code units that are not.  Normally we insert an
+    // entry at zero which goes to the failure label, but if there
+    // was already one there we fall through for success on that entry.
+    // Subsequent entries have alternating meaning (success/failure).
+    RangeBoundaryVector *range_boundaries =
+        alloc->newInfallible<RangeBoundaryVector>(*alloc);
+
+    bool zeroth_entry_is_failure = !cc->is_negated();
+
+    range_boundaries->reserve(last_valid_range);
+    for (int i = 0; i <= last_valid_range; i++) {
+        CharacterRange& range = ranges[i];
+        if (range.from() == 0) {
+            JS_ASSERT(i == 0);
+            zeroth_entry_is_failure = !zeroth_entry_is_failure;
+        } else {
+            range_boundaries->append(range.from());
+        }
+        range_boundaries->append(range.to() + 1);
+    }
+    int end_index = range_boundaries->length() - 1;
+    if ((*range_boundaries)[end_index] > max_char)
+        end_index--;
+
+    jit::Label fall_through;
+    GenerateBranches(macro_assembler,
+                     *range_boundaries,
+                     0,  // start_index.
+                     end_index,
+                     0,  // min_char.
+                     max_char,
+                     &fall_through,
+                     zeroth_entry_is_failure ? &fall_through : on_failure,
+                     zeroth_entry_is_failure ? on_failure : &fall_through);
+    macro_assembler->Bind(&fall_through);
+}
+
+typedef bool EmitCharacterFunction(RegExpCompiler* compiler,
+                                   jschar c,
+                                   jit::Label* on_failure,
+                                   int cp_offset,
+                                   bool check,
+                                   bool preloaded);
+
+static inline bool
+EmitSimpleCharacter(RegExpCompiler* compiler,
+                    jschar c,
+                    jit::Label* on_failure,
+                    int cp_offset,
+                    bool check,
+                    bool preloaded)
+{
+    RegExpMacroAssembler* assembler = compiler->macro_assembler();
+    bool bound_checked = false;
+    if (!preloaded) {
+        assembler->LoadCurrentCharacter(cp_offset, on_failure, check);
+        bound_checked = true;
+    }
+    assembler->CheckNotCharacter(c, on_failure);
+    return bound_checked;
+}
+
+// Only emits non-letters (things that don't have case).  Only used for case
+// independent matches.
+static inline bool
+EmitAtomNonLetter(RegExpCompiler* compiler,
+                  jschar c,
+                  jit::Label* on_failure,
+                  int cp_offset,
+                  bool check,
+                  bool preloaded)
+{
+    RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
+    bool ascii = compiler->ascii();
+    jschar chars[kEcma262UnCanonicalizeMaxWidth];
+    int length = GetCaseIndependentLetters(c, ascii, chars);
+    if (length < 1) {
+        // This can't match.  Must be an ASCII subject and a non-ASCII character.
+        // We do not need to do anything since the ASCII pass already handled this.
+        return false;  // Bounds not checked.
+    }
+    bool checked = false;
+    // We handle the length > 1 case in a later pass.
+    if (length == 1) {
+        if (ascii && c > kMaxOneByteCharCode) {
+            // Can't match - see above.
+            return false;  // Bounds not checked.
+        }
+        if (!preloaded) {
+            macro_assembler->LoadCurrentCharacter(cp_offset, on_failure, check);
+            checked = check;
+        }
+        macro_assembler->CheckNotCharacter(c, on_failure);
+    }
+    return checked;
+}
+
+static bool
+ShortCutEmitCharacterPair(RegExpMacroAssembler* macro_assembler,
+                          bool ascii,
+                          jschar c1,
+                          jschar c2,
+                          jit::Label* on_failure)
+{
+    jschar char_mask = MaximumCharacter(ascii);
+
+    JS_ASSERT(c1 != c2);
+    if (c1 > c2) {
+        jschar tmp = c1;
+        c1 = c2;
+        c2 = tmp;
+    }
+
+    jschar exor = c1 ^ c2;
+    // Check whether exor has only one bit set.
+    if (((exor - 1) & exor) == 0) {
+        // If c1 and c2 differ only by one bit.
+        jschar mask = char_mask ^ exor;
+        macro_assembler->CheckNotCharacterAfterAnd(c1, mask, on_failure);
+        return true;
+    }
+
+    jschar diff = c2 - c1;
+    if (((diff - 1) & diff) == 0 && c1 >= diff) {
+        // If the characters differ by 2^n but don't differ by one bit then
+        // subtract the difference from the found character, then do the or
+        // trick.  We avoid the theoretical case where negative numbers are
+        // involved in order to simplify code generation.
+        jschar mask = char_mask ^ diff;
+        macro_assembler->CheckNotCharacterAfterMinusAnd(c1 - diff,
+                                                        diff,
+                                                        mask,
+                                                        on_failure);
+        return true;
+    }
+    return false;
+}
+
+// Only emits letters (things that have case).  Only used for case independent
+// matches.
+static inline bool
+EmitAtomLetter(RegExpCompiler* compiler,
+               jschar c,
+               jit::Label* on_failure,
+               int cp_offset,
+               bool check,
+               bool preloaded)
+{
+    RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
+    bool ascii = compiler->ascii();
+    jschar chars[kEcma262UnCanonicalizeMaxWidth];
+    int length = GetCaseIndependentLetters(c, ascii, chars);
+    if (length <= 1) return false;
+    // We may not need to check against the end of the input string
+    // if this character lies before a character that matched.
+    if (!preloaded)
+        macro_assembler->LoadCurrentCharacter(cp_offset, on_failure, check);
+    jit::Label ok;
+    JS_ASSERT(kEcma262UnCanonicalizeMaxWidth == 4);
+    switch (length) {
+      case 2: {
+        if (ShortCutEmitCharacterPair(macro_assembler,
+                                      ascii,
+                                      chars[0],
+                                      chars[1],
+                                      on_failure)) {
+        } else {
+            macro_assembler->CheckCharacter(chars[0], &ok);
+            macro_assembler->CheckNotCharacter(chars[1], on_failure);
+            macro_assembler->Bind(&ok);
+        }
+        break;
+      }
+      case 4:
+        macro_assembler->CheckCharacter(chars[3], &ok);
+        // Fall through!
+      case 3:
+        macro_assembler->CheckCharacter(chars[0], &ok);
+        macro_assembler->CheckCharacter(chars[1], &ok);
+        macro_assembler->CheckNotCharacter(chars[2], on_failure);
+        macro_assembler->Bind(&ok);
+        break;
+      default:
+        MOZ_ASSUME_UNREACHABLE("Bad length");
+        break;
+    }
+    return true;
+}
+
+// We call this repeatedly to generate code for each pass over the text node.
+// The passes are in increasing order of difficulty because we hope one
+// of the first passes will fail in which case we are saved the work of the
+// later passes.  for example for the case independent regexp /%[asdfghjkl]a/
+// we will check the '%' in the first pass, the case independent 'a' in the
+// second pass and the character class in the last pass.
+//
+// The passes are done from right to left, so for example to test for /bar/
+// we will first test for an 'r' with offset 2, then an 'a' with offset 1
+// and then a 'b' with offset 0.  This means we can avoid the end-of-input
+// bounds check most of the time.  In the example we only need to check for
+// end-of-input when loading the putative 'r'.
+//
+// A slight complication involves the fact that the first character may already
+// be fetched into a register by the previous node.  In this case we want to
+// do the test for that character first.  We do this in separate passes.  The
+// 'preloaded' argument indicates that we are doing such a 'pass'.  If such a
+// pass has been performed then subsequent passes will have true in
+// first_element_checked to indicate that that character does not need to be
+// checked again.
+//
+// In addition to all this we are passed a Trace, which can
+// contain an AlternativeGeneration object.  In this AlternativeGeneration
+// object we can see details of any quick check that was already passed in
+// order to get to the code we are now generating.  The quick check can involve
+// loading characters, which means we do not need to recheck the bounds
+// up to the limit the quick check already checked.  In addition the quick
+// check can have involved a mask and compare operation which may simplify
+// or obviate the need for further checks at some character positions.
+void
+TextNode::TextEmitPass(RegExpCompiler* compiler,
+                       TextEmitPassType pass,
+                       bool preloaded,
+                       Trace* trace,
+                       bool first_element_checked,
+                       int* checked_up_to)
+{
+    RegExpMacroAssembler* assembler = compiler->macro_assembler();
+    bool ascii = compiler->ascii();
+    jit::Label* backtrack = trace->backtrack();
+    QuickCheckDetails* quick_check = trace->quick_check_performed();
+    int element_count = elements().length();
+    for (int i = preloaded ? 0 : element_count - 1; i >= 0; i--) {
+        TextElement elm = elements()[i];
+        int cp_offset = trace->cp_offset() + elm.cp_offset();
+        if (elm.text_type() == TextElement::ATOM) {
+            const CharacterVector &quarks = elm.atom()->data();
+            for (int j = preloaded ? 0 : quarks.length() - 1; j >= 0; j--) {
+                if (first_element_checked && i == 0 && j == 0) continue;
+                if (DeterminedAlready(quick_check, elm.cp_offset() + j)) continue;
+                EmitCharacterFunction* emit_function = nullptr;
+                switch (pass) {
+                  case NON_ASCII_MATCH:
+                    JS_ASSERT(ascii);
+                    if (quarks[j] > kMaxOneByteCharCode) {
+                        assembler->JumpOrBacktrack(backtrack);
+                        return;
+                    }
+                    break;
+                  case NON_LETTER_CHARACTER_MATCH:
+                    emit_function = &EmitAtomNonLetter;
+                    break;
+                  case SIMPLE_CHARACTER_MATCH:
+                    emit_function = &EmitSimpleCharacter;
+                    break;
+                  case CASE_CHARACTER_MATCH:
+                    emit_function = &EmitAtomLetter;
+                    break;
+                  default:
+                    break;
+                }
+                if (emit_function != nullptr) {
+                    bool bound_checked = emit_function(compiler,
+                                                       quarks[j],
+                                                       backtrack,
+                                                       cp_offset + j,
+                                                       *checked_up_to < cp_offset + j,
+                                                       preloaded);
+                    if (bound_checked) UpdateBoundsCheck(cp_offset + j, checked_up_to);
+                }
+            }
+        } else {
+            JS_ASSERT(TextElement::CHAR_CLASS == elm.text_type());
+            if (pass == CHARACTER_CLASS_MATCH) {
+                if (first_element_checked && i == 0) continue;
+                if (DeterminedAlready(quick_check, elm.cp_offset())) continue;
+                RegExpCharacterClass* cc = elm.char_class();
+                EmitCharClass(alloc(),
+                              assembler,
+                              cc,
+                              ascii,
+                              backtrack,
+                              cp_offset,
+                              *checked_up_to < cp_offset,
+                              preloaded);
+                UpdateBoundsCheck(cp_offset, checked_up_to);
+            }
+        }
+    }
+}
+
+int
+TextNode::Length()
+{
+    TextElement elm = elements()[elements().length() - 1];
+    JS_ASSERT(elm.cp_offset() >= 0);
+    return elm.cp_offset() + elm.length();
+}
+
+bool
+TextNode::SkipPass(int int_pass, bool ignore_case)
+{
+    TextEmitPassType pass = static_cast<TextEmitPassType>(int_pass);
+    if (ignore_case)
+        return pass == SIMPLE_CHARACTER_MATCH;
+    return pass == NON_LETTER_CHARACTER_MATCH || pass == CASE_CHARACTER_MATCH;
+}
+
+// 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.  For efficiency we do not do this in a single
+// pass from left to right.  Instead we pass over the text node several times,
+// emitting code for some character positions every time.  See the comment on
+// TextEmitPass for details.
+void
+TextNode::Emit(RegExpCompiler* compiler, Trace* trace)
+{
+    LimitResult limit_result = LimitVersions(compiler, trace);
+    if (limit_result == DONE) return;
+    JS_ASSERT(limit_result == CONTINUE);
+
+    if (trace->cp_offset() + Length() > RegExpMacroAssembler::kMaxCPOffset) {
+        compiler->SetRegExpTooBig();
+        return;
+    }
+
+    if (compiler->ascii()) {
+        int dummy = 0;
+        TextEmitPass(compiler, NON_ASCII_MATCH, false, trace, false, &dummy);
+    }
+
+    bool first_elt_done = false;
+    int bound_checked_to = trace->cp_offset() - 1;
+    bound_checked_to += trace->bound_checked_up_to();
+
+    // If a character is preloaded into the current character register then
+    // check that now.
+    if (trace->characters_preloaded() == 1) {
+        for (int pass = kFirstRealPass; pass <= kLastPass; pass++) {
+            if (!SkipPass(pass, compiler->ignore_case())) {
+                TextEmitPass(compiler,
+                             static_cast<TextEmitPassType>(pass),
+                             true,
+                             trace,
+                             false,
+                             &bound_checked_to);
+            }
+        }
+        first_elt_done = true;
+    }
+
+    for (int pass = kFirstRealPass; pass <= kLastPass; pass++) {
+        if (!SkipPass(pass, compiler->ignore_case())) {
+            TextEmitPass(compiler,
+                         static_cast<TextEmitPassType>(pass),
+                         false,
+                         trace,
+                         first_elt_done,
+                         &bound_checked_to);
+        }
+    }
+
+    Trace successor_trace(*trace);
+    successor_trace.set_at_start(false);
+    successor_trace.AdvanceCurrentPositionInTrace(Length(), compiler);
+    RecursionCheck rc(compiler);
+    on_success()->Emit(compiler, &successor_trace);
+}
+
+void
+LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace)
+{
+    RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
+    if (trace->stop_node() == this) {
+        int text_length =
+            GreedyLoopTextLengthForAlternative(&alternatives()[0]);
+        JS_ASSERT(text_length != kNodeIsTooComplexForGreedyLoops);
+        // Update the counter-based backtracking info on the stack.  This is an
+        // optimization for greedy loops (see below).
+        JS_ASSERT(trace->cp_offset() == text_length);
+        macro_assembler->AdvanceCurrentPosition(text_length);
+        macro_assembler->JumpOrBacktrack(trace->loop_label());
+        return;
+    }
+    JS_ASSERT(trace->stop_node() == nullptr);
+    if (!trace->is_trivial()) {
+        trace->Flush(compiler, this);
+        return;
+    }
+    ChoiceNode::Emit(compiler, trace);
+}
+
+/* Code generation for choice nodes.
+ *
+ * We generate quick checks that do a mask and compare to eliminate a
+ * choice.  If the quick check succeeds then it jumps to the continuation to
+ * do slow checks and check subsequent nodes.  If it fails (the common case)
+ * it falls through to the next choice.
+ *
+ * Here is the desired flow graph.  Nodes directly below each other imply
+ * fallthrough.  Alternatives 1 and 2 have quick checks.  Alternative
+ * 3 doesn't have a quick check so we have to call the slow check.
+ * Nodes are marked Qn for quick checks and Sn for slow checks.  The entire
+ * regexp continuation is generated directly after the Sn node, up to the
+ * next JumpOrBacktrack if we decide to reuse some already generated code.  Some
+ * nodes expect preload_characters to be preloaded into the current
+ * character register.  R nodes do this preloading.  Vertices are marked
+ * F for failures and S for success (possible success in the case of quick
+ * nodes).  L, V, < and > are used as arrow heads.
+ *
+ * ----------> R
+ *             |
+ *             V
+ *            Q1 -----> S1
+ *             |   S   /
+ *            F|      /
+ *             |    F/
+ *             |    /
+ *             |   R
+ *             |  /
+ *             V L
+ *            Q2 -----> S2
+ *             |   S   /
+ *            F|      /
+ *             |    F/
+ *             |    /
+ *             |   R
+ *             |  /
+ *             V L
+ *            S3
+ *             |
+ *            F|
+ *             |
+ *             R
+ *             |
+ * backtrack   V
+ * <----------Q4
+ *   \    F    |
+ *    \        |S
+ *     \   F   V
+ *      \-----S4
+ *
+ * For greedy loops we reverse our expectation and expect to match rather
+ * than fail. Therefore we want the loop code to look like this (U is the
+ * unwind code that steps back in the greedy loop).  The following alternatives
+ * look the same as above.
+ *              _____
+ *             /     \
+ *             V     |
+ * ----------> S1    |
+ *            /|     |
+ *           / |S    |
+ *         F/  \_____/
+ *         /
+ *        |<-----------
+ *        |            \
+ *        V             \
+ *        Q2 ---> S2     \
+ *        |  S   /       |
+ *       F|     /        |
+ *        |   F/         |
+ *        |   /          |
+ *        |  R           |
+ *        | /            |
+ *   F    VL             |
+ * <------U              |
+ * back   |S             |
+ *        \______________/
+ */
+
+// This class is used when generating the alternatives in a choice node.  It
+// records the way the alternative is being code generated.
+class irregexp::AlternativeGeneration
+{
+  public:
+    AlternativeGeneration()
+      : possible_success(),
+        expects_preload(false),
+        after(),
+        quick_check_details()
+    {}
+
+    jit::Label possible_success;
+    bool expects_preload;
+    jit::Label after;
+    QuickCheckDetails quick_check_details;
+};
+
+void
+ChoiceNode::GenerateGuard(RegExpMacroAssembler* macro_assembler,
+                          Guard* guard, Trace* trace)
+{
+    switch (guard->op()) {
+      case Guard::LT:
+        JS_ASSERT(!trace->mentions_reg(guard->reg()));
+        macro_assembler->IfRegisterGE(guard->reg(),
+                                      guard->value(),
+                                      trace->backtrack());
+        break;
+      case Guard::GEQ:
+        JS_ASSERT(!trace->mentions_reg(guard->reg()));
+        macro_assembler->IfRegisterLT(guard->reg(),
+                                      guard->value(),
+                                      trace->backtrack());
+        break;
+    }
+}
+
+int
+ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler, int eats_at_least)
+{
+    int preload_characters = Min(4, eats_at_least);
+    if (compiler->macro_assembler()->CanReadUnaligned()) {
+        bool ascii = compiler->ascii();
+        if (ascii) {
+            if (preload_characters > 4)
+                preload_characters = 4;
+            // We can't preload 3 characters because there is no machine instruction
+            // to do that.  We can't just load 4 because we could be reading
+            // beyond the end of the string, which could cause a memory fault.
+            if (preload_characters == 3)
+                preload_characters = 2;
+        } else {
+            if (preload_characters > 2)
+                preload_characters = 2;
+        }
+    } else {
+        if (preload_characters > 1)
+            preload_characters = 1;
+    }
+    return preload_characters;
+}
+
+RegExpNode *
+TextNode::GetSuccessorOfOmnivorousTextNode(RegExpCompiler* compiler)
+{
+    if (elements().length() != 1)
+        return nullptr;
+
+    TextElement elm = elements()[0];
+    if (elm.text_type() != TextElement::CHAR_CLASS)
+        return nullptr;
+
+    RegExpCharacterClass* node = elm.char_class();
+    CharacterRangeVector &ranges = node->ranges(alloc());
+
+    if (!CharacterRange::IsCanonical(ranges))
+        CharacterRange::Canonicalize(ranges);
+
+    if (node->is_negated())
+        return ranges.length() == 0 ? on_success() : nullptr;
+
+    if (ranges.length() != 1)
+        return nullptr;
+
+    uint32_t max_char = MaximumCharacter(compiler->ascii());
+    return ranges[0].IsEverything(max_char) ? on_success() : nullptr;
+}
+
+// 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::GreedyLoopTextLengthForAlternative(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;
+        }
+        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;
+}
+
+// Creates a list of AlternativeGenerations.  If the list has a reasonable
+// size then it is on the stack, otherwise the excess is on the heap.
+class AlternativeGenerationList
+{
+  public:
+    AlternativeGenerationList(LifoAlloc *alloc, size_t count)
+      : alt_gens_(*alloc)
+    {
+        alt_gens_.reserve(count);
+        for (size_t i = 0; i < count && i < kAFew; i++)
+            alt_gens_.append(a_few_alt_gens_ + i);
+        for (size_t i = kAFew; i < count; i++)
+            alt_gens_.append(js_new<AlternativeGeneration>());
+    }
+
+    ~AlternativeGenerationList() {
+        for (size_t i = kAFew; i < alt_gens_.length(); i++) {
+            js_delete(alt_gens_[i]);
+            alt_gens_[i] = nullptr;
+        }
+    }
+
+    AlternativeGeneration *at(int i) {
+        return alt_gens_[i];
+    }
+
+  private:
+    static const size_t kAFew = 10;
+    js::Vector<AlternativeGeneration *, 1, LifoAllocPolicy<Infallible> > alt_gens_;
+    AlternativeGeneration a_few_alt_gens_[kAFew];
+};
+
+void
+ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace)
+{
+    RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
+    size_t choice_count = alternatives().length();
+#ifdef DEBUG
+    for (size_t i = 0; i < choice_count - 1; i++) {
+        const GuardedAlternative &alternative = alternatives()[i];
+        const GuardVector *guards = alternative.guards();
+        if (guards) {
+            for (size_t j = 0; j < guards->length(); j++)
+                JS_ASSERT(!trace->mentions_reg((*guards)[j]->reg()));
+        }
+    }
+#endif
+
+    LimitResult limit_result = LimitVersions(compiler, trace);
+    if (limit_result == DONE) return;
+    JS_ASSERT(limit_result == CONTINUE);
+
+    int new_flush_budget = trace->flush_budget() / choice_count;
+    if (trace->flush_budget() == 0 && trace->actions() != nullptr) {
+        trace->Flush(compiler, this);
+        return;
+    }
+
+    RecursionCheck rc(compiler);
+
+    Trace* current_trace = trace;
+
+    int text_length = GreedyLoopTextLengthForAlternative(&alternatives()[0]);
+    bool greedy_loop = false;
+    jit::Label greedy_loop_label;
+    Trace counter_backtrack_trace;
+    counter_backtrack_trace.set_backtrack(&greedy_loop_label);
+    if (not_at_start()) counter_backtrack_trace.set_at_start(false);
+
+    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;
+        JS_ASSERT(trace->stop_node() == nullptr);
+        macro_assembler->PushCurrentPosition();
+        current_trace = &counter_backtrack_trace;
+        jit::Label greedy_match_failed;
+        Trace greedy_match_trace;
+        if (not_at_start()) greedy_match_trace.set_at_start(false);
+        greedy_match_trace.set_backtrack(&greedy_match_failed);
+        jit::Label loop_label;
+        macro_assembler->Bind(&loop_label);
+        greedy_match_trace.set_stop_node(this);
+        greedy_match_trace.set_loop_label(&loop_label);
+        alternatives()[0].node()->Emit(compiler, &greedy_match_trace);
+        macro_assembler->Bind(&greedy_match_failed);
+    }
+
+    jit::Label second_choice;  // For use in greedy matches.
+    macro_assembler->Bind(&second_choice);
+
+    size_t first_normal_choice = greedy_loop ? 1 : 0;
+
+    bool not_at_start = current_trace->at_start() == Trace::FALSE_VALUE;
+    const int kEatsAtLeastNotYetInitialized = -1;
+    int eats_at_least = kEatsAtLeastNotYetInitialized;
+
+    bool skip_was_emitted = false;
+
+    if (!greedy_loop && choice_count == 2) {
+        GuardedAlternative alt1 = alternatives()[1];
+        if (!alt1.guards() || alt1.guards()->length() == 0) {
+            RegExpNode* eats_anything_node = alt1.node();
+            if (eats_anything_node->GetSuccessorOfOmnivorousTextNode(compiler) == this) {
+                // At this point we know that we are at a non-greedy loop that will eat
+                // any character one at a time.  Any non-anchored regexp has such a
+                // loop prepended to it in order to find where it starts.  We look for
+                // a pattern of the form ...abc... where we can look 6 characters ahead
+                // and step forwards 3 if the character is not one of abc.  Abc need
+                // not be atoms, they can be any reasonably limited character class or
+                // small alternation.
+                JS_ASSERT(trace->is_trivial());  // This is the case on LoopChoiceNodes.
+                BoyerMooreLookahead* lookahead = bm_info(not_at_start);
+                if (lookahead == nullptr) {
+                    eats_at_least = Min(kMaxLookaheadForBoyerMoore,
+                                        EatsAtLeast(kMaxLookaheadForBoyerMoore,
+                                                    kRecursionBudget,
+                                                    not_at_start));
+                    if (eats_at_least >= 1) {
+                        BoyerMooreLookahead* bm =
+                            alloc()->newInfallible<BoyerMooreLookahead>(alloc(), eats_at_least, compiler);
+                        GuardedAlternative alt0 = alternatives()[0];
+                        alt0.node()->FillInBMInfo(0, kRecursionBudget, bm, not_at_start);
+                        skip_was_emitted = bm->EmitSkipInstructions(macro_assembler);
+                    }
+                } else {
+                    skip_was_emitted = lookahead->EmitSkipInstructions(macro_assembler);
+                }
+            }
+        }
+    }
+
+    if (eats_at_least == kEatsAtLeastNotYetInitialized) {
+        // Save some time by looking at most one machine word ahead.
+        eats_at_least =
+            EatsAtLeast(compiler->ascii() ? 4 : 2, kRecursionBudget, not_at_start);
+    }
+    int preload_characters = CalculatePreloadCharacters(compiler, eats_at_least);
+
+    bool preload_is_current = !skip_was_emitted &&
+        (current_trace->characters_preloaded() == preload_characters);
+    bool preload_has_checked_bounds = preload_is_current;
+
+    AlternativeGenerationList alt_gens(alloc(), choice_count);
+
+    // 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 (size_t i = first_normal_choice; i < choice_count; i++) {
+        GuardedAlternative alternative = alternatives()[i];
+        AlternativeGeneration* alt_gen = alt_gens.at(i);
+        alt_gen->quick_check_details.set_characters(preload_characters);
+        const GuardVector *guards = alternative.guards();
+        Trace new_trace(*current_trace);
+        new_trace.set_characters_preloaded(preload_is_current ?
+                                           preload_characters :
+                                           0);
+        if (preload_has_checked_bounds) {
+            new_trace.set_bound_checked_up_to(preload_characters);
+        }
+        new_trace.quick_check_performed()->Clear();
+        if (not_at_start_) new_trace.set_at_start(Trace::FALSE_VALUE);
+        alt_gen->expects_preload = preload_is_current;
+        bool generate_full_check_inline = false;
+        if (try_to_emit_quick_check_for_alternative(i) &&
+            alternative.node()->EmitQuickCheck(compiler,
+                                               &new_trace,
+                                               preload_has_checked_bounds,
+                                               &alt_gen->possible_success,
+                                               &alt_gen->quick_check_details,
+                                               i < choice_count - 1)) {
+            // Quick check was generated for this choice.
+            preload_is_current = true;
+            preload_has_checked_bounds = true;
+            // On the last choice in the ChoiceNode we generated the quick
+            // check to fall through on possible success.  So now we need to
+            // generate the full check inline.
+            if (i == choice_count - 1) {
+                macro_assembler->Bind(&alt_gen->possible_success);
+                new_trace.set_quick_check_performed(&alt_gen->quick_check_details);
+                new_trace.set_characters_preloaded(preload_characters);
+                new_trace.set_bound_checked_up_to(preload_characters);
+                generate_full_check_inline = true;
+            }
+        } else if (alt_gen->quick_check_details.cannot_match()) {
+            if (i == choice_count - 1 && !greedy_loop) {
+                macro_assembler->JumpOrBacktrack(trace->backtrack());
+            }
+            continue;
+        } else {
+            // No quick check was generated.  Put the full code here.
+            // If this is not the first choice then there could be slow checks from
+            // previous cases that go here when they fail.  There's no reason to
+            // insist that they preload characters since the slow check we are about
+            // to generate probably can't use it.
+            if (i != first_normal_choice) {
+                alt_gen->expects_preload = false;
+                new_trace.InvalidateCurrentCharacter();
+            }
+            if (i < choice_count - 1) {
+                new_trace.set_backtrack(&alt_gen->after);
+            }
+            generate_full_check_inline = true;
+        }
+        if (generate_full_check_inline) {
+            if (new_trace.actions() != nullptr)
+                new_trace.set_flush_budget(new_flush_budget);
+            if (guards) {
+                for (size_t j = 0; j < guards->length(); j++)
+                    GenerateGuard(macro_assembler, (*guards)[j], &new_trace);
+            }
+            alternative.node()->Emit(compiler, &new_trace);
+            preload_is_current = false;
+        }
+        macro_assembler->Bind(&alt_gen->after);
+    }
+    if (greedy_loop) {
+        macro_assembler->Bind(&greedy_loop_label);
+        // If we have unwound to the bottom then backtrack.
+        macro_assembler->CheckGreedyLoop(trace->backtrack());
+        // Otherwise try the second priority at an earlier position.
+        macro_assembler->AdvanceCurrentPosition(-text_length);
+        macro_assembler->JumpOrBacktrack(&second_choice);
+    }
+
+    // At this point we need to generate slow checks for the alternatives where
+    // the quick check was inlined.  We can recognize these because the associated
+    // label was bound.
+    for (size_t i = first_normal_choice; i < choice_count - 1; i++) {
+        AlternativeGeneration* alt_gen = alt_gens.at(i);
+        Trace new_trace(*current_trace);
+        // If there are actions to be flushed we have to limit how many times
+        // they are flushed.  Take the budget of the parent trace and distribute
+        // it fairly amongst the children.
+        if (new_trace.actions() != nullptr) {
+            new_trace.set_flush_budget(new_flush_budget);
+        }
+        EmitOutOfLineContinuation(compiler,
+                                  &new_trace,
+                                  alternatives()[i],
+                                  alt_gen,
+                                  preload_characters,
+                                  alt_gens.at(i + 1)->expects_preload);
+    }
+}
+
+void
+ChoiceNode::EmitOutOfLineContinuation(RegExpCompiler* compiler,
+                                      Trace* trace,
+                                      GuardedAlternative alternative,
+                                      AlternativeGeneration* alt_gen,
+                                      int preload_characters,
+                                      bool next_expects_preload)
+{
+    if (!alt_gen->possible_success.used())
+        return;
+
+    RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
+    macro_assembler->Bind(&alt_gen->possible_success);
+    Trace out_of_line_trace(*trace);
+    out_of_line_trace.set_characters_preloaded(preload_characters);
+    out_of_line_trace.set_quick_check_performed(&alt_gen->quick_check_details);
+    if (not_at_start_) out_of_line_trace.set_at_start(Trace::FALSE_VALUE);
+    const GuardVector *guards = alternative.guards();
+    if (next_expects_preload) {
+        jit::Label reload_current_char;
+        out_of_line_trace.set_backtrack(&reload_current_char);
+        if (guards) {
+            for (size_t j = 0; j < guards->length(); j++)
+                GenerateGuard(macro_assembler, (*guards)[j], &out_of_line_trace);
+        }
+        alternative.node()->Emit(compiler, &out_of_line_trace);
+        macro_assembler->Bind(&reload_current_char);
+        // Reload the current character, since the next quick check expects that.
+        // We don't need to check bounds here because we only get into this
+        // code through a quick check which already did the checked load.
+        macro_assembler->LoadCurrentCharacter(trace->cp_offset(),
+                                              nullptr,
+                                              false,
+                                              preload_characters);
+        macro_assembler->JumpOrBacktrack(&(alt_gen->after));
+    } else {
+        out_of_line_trace.set_backtrack(&(alt_gen->after));
+        if (guards) {
+            for (size_t j = 0; j < guards->length(); j++)
+                GenerateGuard(macro_assembler, (*guards)[j], &out_of_line_trace);
+        }
+        alternative.node()->Emit(compiler, &out_of_line_trace);
+    }
+}
+
+void
+ActionNode::Emit(RegExpCompiler* compiler, Trace* trace)
+{
+    RegExpMacroAssembler* assembler = compiler->macro_assembler();
+    LimitResult limit_result = LimitVersions(compiler, trace);
+    if (limit_result == DONE) return;
+    JS_ASSERT(limit_result == CONTINUE);
+
+    RecursionCheck rc(compiler);
+
+    switch (action_type_) {
+      case STORE_POSITION: {
+        Trace::DeferredCapture
+            new_capture(data_.u_position_register.reg,
+                        data_.u_position_register.is_capture,
+                        trace);
+        Trace new_trace = *trace;
+        new_trace.add_action(&new_capture);
+        on_success()->Emit(compiler, &new_trace);
+        break;
+      }
+      case INCREMENT_REGISTER: {
+        Trace::DeferredIncrementRegister
+            new_increment(data_.u_increment_register.reg);
+        Trace new_trace = *trace;
+        new_trace.add_action(&new_increment);
+        on_success()->Emit(compiler, &new_trace);
+        break;
+      }
+      case SET_REGISTER: {
+        Trace::DeferredSetRegister
+            new_set(data_.u_store_register.reg, data_.u_store_register.value);
+        Trace new_trace = *trace;
+        new_trace.add_action(&new_set);
+        on_success()->Emit(compiler, &new_trace);
+        break;
+      }
+      case CLEAR_CAPTURES: {
+        Trace::DeferredClearCaptures
+            new_capture(Interval(data_.u_clear_captures.range_from,
+                                 data_.u_clear_captures.range_to));
+        Trace new_trace = *trace;
+        new_trace.add_action(&new_capture);
+        on_success()->Emit(compiler, &new_trace);
+        break;
+      }
+      case BEGIN_SUBMATCH:
+        if (!trace->is_trivial()) {
+            trace->Flush(compiler, this);
+        } else {
+            assembler->WriteCurrentPositionToRegister(data_.u_submatch.current_position_register, 0);
+            assembler->WriteBacktrackStackPointerToRegister(data_.u_submatch.stack_pointer_register);
+            on_success()->Emit(compiler, trace);
+        }
+        break;
+      case EMPTY_MATCH_CHECK: {
+        int start_pos_reg = data_.u_empty_match_check.start_register;
+        int stored_pos = 0;
+        int rep_reg = data_.u_empty_match_check.repetition_register;
+        bool has_minimum = (rep_reg != RegExpCompiler::kNoRegister);
+        bool know_dist = trace->GetStoredPosition(start_pos_reg, &stored_pos);
+        if (know_dist && !has_minimum && stored_pos == trace->cp_offset()) {
+            // If we know we haven't advanced and there is no minimum we
+            // can just backtrack immediately.
+            assembler->JumpOrBacktrack(trace->backtrack());
+        } else if (know_dist && stored_pos < trace->cp_offset()) {
+            // If we know we've advanced we can generate the continuation
+            // immediately.
+            on_success()->Emit(compiler, trace);
+        } else if (!trace->is_trivial()) {
+            trace->Flush(compiler, this);
+        } else {
+            jit::Label skip_empty_check;
+            // If we have a minimum number of repetitions we check the current
+            // number first and skip the empty check if it's not enough.
+            if (has_minimum) {
+                int limit = data_.u_empty_match_check.repetition_limit;
+                assembler->IfRegisterLT(rep_reg, limit, &skip_empty_check);
+            }
+            // If the match is empty we bail out, otherwise we fall through
+            // to the on-success continuation.
+            assembler->IfRegisterEqPos(data_.u_empty_match_check.start_register,
+                                       trace->backtrack());
+            assembler->Bind(&skip_empty_check);
+            on_success()->Emit(compiler, trace);
+        }
+        break;
+      }
+      case POSITIVE_SUBMATCH_SUCCESS: {
+        if (!trace->is_trivial()) {
+            trace->Flush(compiler, this);
+            return;
+        }
+        assembler->ReadCurrentPositionFromRegister(data_.u_submatch.current_position_register);
+        assembler->ReadBacktrackStackPointerFromRegister(data_.u_submatch.stack_pointer_register);
+        int clear_register_count = data_.u_submatch.clear_register_count;
+        if (clear_register_count == 0) {
+            on_success()->Emit(compiler, trace);
+            return;
+        }
+        int clear_registers_from = data_.u_submatch.clear_register_from;
+        jit::Label clear_registers_backtrack;
+        Trace new_trace = *trace;
+        new_trace.set_backtrack(&clear_registers_backtrack);
+        on_success()->Emit(compiler, &new_trace);
+
+        assembler->Bind(&clear_registers_backtrack);
+        int clear_registers_to = clear_registers_from + clear_register_count - 1;
+        assembler->ClearRegisters(clear_registers_from, clear_registers_to);
+
+        JS_ASSERT(trace->backtrack() == nullptr);
+        assembler->Backtrack();
+        return;
+      }
+      default:
+        MOZ_ASSUME_UNREACHABLE("Bad action");
+    }
+}
+
+void
+BackReferenceNode::Emit(RegExpCompiler* compiler, Trace* trace)
+{
+    RegExpMacroAssembler* assembler = compiler->macro_assembler();
+    if (!trace->is_trivial()) {
+        trace->Flush(compiler, this);
+        return;
+    }
+
+    LimitResult limit_result = LimitVersions(compiler, trace);
+    if (limit_result == DONE) return;
+    JS_ASSERT(limit_result == CONTINUE);
+
+    RecursionCheck rc(compiler);
+
+    JS_ASSERT(start_reg_ + 1 == end_reg_);
+    if (compiler->ignore_case()) {
+        assembler->CheckNotBackReferenceIgnoreCase(start_reg_,
+                                                   trace->backtrack());
+    } else {
+        assembler->CheckNotBackReference(start_reg_, trace->backtrack());
+    }
+    on_success()->Emit(compiler, trace);
+}
+
+RegExpNode::LimitResult
+RegExpNode::LimitVersions(RegExpCompiler* compiler, Trace* trace)
+{
+    // If we are generating a greedy loop then don't stop and don't reuse code.
+    if (trace->stop_node() != nullptr)
+        return CONTINUE;
+
+    RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
+    if (trace->is_trivial()) {
+        if (label()->bound()) {
+            // We are being asked to generate a generic version, but that's already
+            // been done so just go to it.
+            macro_assembler->JumpOrBacktrack(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->JumpOrBacktrack(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.
+    trace_count_++;
+    if (trace_count_ < kMaxCopiesCodeGenerated &&
+        compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) {
+        return CONTINUE;
+    }
+
+    // If we get here code has been generated for this node too many times or
+    // recursion is too deep.  Time to switch to a generic version.  The code for
+    // generic versions above can handle deep recursion properly.
+    trace->Flush(compiler, this);
+    return DONE;
+}
+
+bool
+RegExpNode::EmitQuickCheck(RegExpCompiler* compiler,
+                           Trace* trace,
+                           bool preload_has_checked_bounds,
+                           jit::Label* on_possible_success,
+                           QuickCheckDetails* details,
+                           bool fall_through_on_failure)
+{
+    if (details->characters() == 0) return false;
+    GetQuickCheckDetails(
+                         details, compiler, 0, trace->at_start() == Trace::FALSE_VALUE);
+    if (details->cannot_match()) return false;
+    if (!details->Rationalize(compiler->ascii())) return false;
+    JS_ASSERT(details->characters() == 1 ||
+              compiler->macro_assembler()->CanReadUnaligned());
+    uint32_t mask = details->mask();
+    uint32_t value = details->value();
+
+    RegExpMacroAssembler* assembler = compiler->macro_assembler();
+
+    if (trace->characters_preloaded() != details->characters()) {
+        assembler->LoadCurrentCharacter(trace->cp_offset(),
+                                        trace->backtrack(),
+                                        !preload_has_checked_bounds,
+                                        details->characters());
+    }
+
+    bool need_mask = true;
+
+    if (details->characters() == 1) {
+        // If number of characters preloaded is 1 then we used a byte or 16 bit
+        // load so the value is already masked down.
+        uint32_t char_mask = MaximumCharacter(compiler->ascii());
+        if ((mask & char_mask) == char_mask) need_mask = false;
+        mask &= char_mask;
+    } else {
+        // For 2-character preloads in ASCII mode or 1-character preloads in
+        // TWO_BYTE mode we also use a 16 bit load with zero extend.
+        if (details->characters() == 2 && compiler->ascii()) {
+            if ((mask & 0xffff) == 0xffff) need_mask = false;
+        } else if (details->characters() == 1 && !compiler->ascii()) {
+            if ((mask & 0xffff) == 0xffff) need_mask = false;
+        } else {
+            if (mask == 0xffffffff) need_mask = false;
+        }
+    }
+
+    if (fall_through_on_failure) {
+        if (need_mask) {
+            assembler->CheckCharacterAfterAnd(value, mask, on_possible_success);
+        } else {
+            assembler->CheckCharacter(value, on_possible_success);
+        }
+    } else {
+        if (need_mask) {
+            assembler->CheckNotCharacterAfterAnd(value, mask, trace->backtrack());
+        } else {
+            assembler->CheckNotCharacter(value, trace->backtrack());
+        }
+    }
+    return true;
+}
+
+void
+TextNode::FillInBMInfo(int initial_offset,
+                       int budget,
+                       BoyerMooreLookahead* bm,
+                       bool not_at_start)
+{
+    if (initial_offset >= bm->length())
+        return;
+
+    int offset = initial_offset;
+    int max_char = bm->max_char();
+    for (size_t i = 0; i < elements().length(); i++) {
+        if (offset >= bm->length()) {
+            if (initial_offset == 0)
+                set_bm_info(not_at_start, bm);
+            return;
+        }
+        TextElement text = elements()[i];
+        if (text.text_type() == TextElement::ATOM) {
+            RegExpAtom* atom = text.atom();
+            for (int j = 0; j < atom->length(); j++, offset++) {
+                if (offset >= bm->length()) {
+                    if (initial_offset == 0)
+                        set_bm_info(not_at_start, bm);
+                    return;
+                }
+                jschar character = atom->data()[j];
+                if (bm->compiler()->ignore_case()) {
+                    jschar chars[kEcma262UnCanonicalizeMaxWidth];
+                    int length = GetCaseIndependentLetters(character,
+                                                           bm->max_char() == kMaxOneByteCharCode,
+                                                           chars);
+                    for (int j = 0; j < length; j++)
+                        bm->Set(offset, chars[j]);
+                } else {
+                    if (character <= max_char) bm->Set(offset, character);
+                }
+            }
+        } else {
+            JS_ASSERT(TextElement::CHAR_CLASS == text.text_type());
+            RegExpCharacterClass* char_class = text.char_class();
+            const CharacterRangeVector &ranges = char_class->ranges(alloc());
+            if (char_class->is_negated()) {
+                bm->SetAll(offset);
+            } else {
+                for (size_t k = 0; k < ranges.length(); k++) {
+                    const CharacterRange &range = ranges[k];
+                    if (range.from() > max_char)
+                        continue;
+                    int to = Min(max_char, static_cast<int>(range.to()));
+                    bm->SetInterval(offset, Interval(range.from(), to));
+                }
+            }
+            offset++;
+        }
+    }
+    if (offset >= bm->length()) {
+        if (initial_offset == 0) set_bm_info(not_at_start, bm);
+        return;
+    }
+    on_success()->FillInBMInfo(offset,
+                               budget - 1,
+                               bm,
+                               true);  // Not at start after a text node.
+    if (initial_offset == 0)
+        set_bm_info(not_at_start, bm);
+}
+
+// -------------------------------------------------------------------
+// QuickCheckDetails
+
+// Takes the left-most 1-bit and smears it out, setting all bits to its right.
+static inline uint32_t
+SmearBitsRight(uint32_t v)
+{
+    v |= v >> 1;
+    v |= v >> 2;
+    v |= v >> 4;
+    v |= v >> 8;
+    v |= v >> 16;
+    return v;
+}
+
+// Here is the meat of GetQuickCheckDetails (see also the comment on the
+// super-class in the .h file).
+//
+// We iterate along the text object, building up for each character a
+// mask and value that can be used to test for a quick failure to match.
+// The masks and values for the positions will be combined into a single
+// machine word for the current character width in order to be used in
+// generating a quick check.
+void
+TextNode::GetQuickCheckDetails(QuickCheckDetails* details,
+                               RegExpCompiler* compiler,
+                               int characters_filled_in,
+                               bool not_at_start)
+{
+    JS_ASSERT(characters_filled_in < details->characters());
+    int characters = details->characters();
+    int char_mask = MaximumCharacter(compiler->ascii());
+
+    for (size_t k = 0; k < elements().length(); k++) {
+        TextElement elm = elements()[k];
+        if (elm.text_type() == TextElement::ATOM) {
+            const CharacterVector &quarks = elm.atom()->data();
+            for (size_t i = 0; i < (size_t) characters && i < quarks.length(); i++) {
+                QuickCheckDetails::Position* pos =
+                    details->positions(characters_filled_in);
+                jschar c = quarks[i];
+                if (c > char_mask) {
+                    // If we expect a non-ASCII character from an ASCII string,
+                    // there is no way we can match. Not even case independent
+                    // matching can turn an ASCII character into non-ASCII or
+                    // vice versa.
+                    details->set_cannot_match();
+                    pos->determines_perfectly = false;
+                    return;
+                }
+                if (compiler->ignore_case()) {
+                    jschar chars[kEcma262UnCanonicalizeMaxWidth];
+                    size_t length = GetCaseIndependentLetters(c, compiler->ascii(), chars);
+                    JS_ASSERT(length != 0);  // Can only happen if c > char_mask (see above).
+                    if (length == 1) {
+                        // This letter has no case equivalents, so it's nice and simple
+                        // and the mask-compare will determine definitely whether we have
+                        // a match at this character position.
+                        pos->mask = char_mask;
+                        pos->value = c;
+                        pos->determines_perfectly = true;
+                    } else {
+                        uint32_t common_bits = char_mask;
+                        uint32_t bits = chars[0];
+                        for (size_t j = 1; j < length; j++) {
+                            uint32_t differing_bits = ((chars[j] & common_bits) ^ bits);
+                            common_bits ^= differing_bits;
+                            bits &= common_bits;
+                        }
+                        // If length is 2 and common bits has only one zero in it then
+                        // our mask and compare instruction will determine definitely
+                        // whether we have a match at this character position.  Otherwise
+                        // it can only be an approximate check.
+                        uint32_t one_zero = (common_bits | ~char_mask);
+                        if (length == 2 && ((~one_zero) & ((~one_zero) - 1)) == 0) {
+                            pos->determines_perfectly = true;
+                        }
+                        pos->mask = common_bits;
+                        pos->value = bits;
+                    }
+                } else {
+                    // Don't ignore case.  Nice simple case where the mask-compare will
+                    // determine definitely whether we have a match at this character
+                    // position.
+                    pos->mask = char_mask;
+                    pos->value = c;
+                    pos->determines_perfectly = true;
+                }
+                characters_filled_in++;
+                JS_ASSERT(characters_filled_in <= details->characters());
+                if (characters_filled_in == details->characters()) {
+                    return;
+                }
+            }
+        } else {
+            QuickCheckDetails::Position* pos =
+                details->positions(characters_filled_in);
+            RegExpCharacterClass* tree = elm.char_class();
+            const CharacterRangeVector &ranges = tree->ranges(alloc());
+            if (tree->is_negated()) {
+                // A quick check uses multi-character mask and compare.  There is no
+                // useful way to incorporate a negative char class into this scheme
+                // so we just conservatively create a mask and value that will always
+                // succeed.
+                pos->mask = 0;
+                pos->value = 0;
+            } else {
+                size_t first_range = 0;
+                while (ranges[first_range].from() > char_mask) {
+                    first_range++;
+                    if (first_range == ranges.length()) {
+                        details->set_cannot_match();
+                        pos->determines_perfectly = false;
+                        return;
+                    }
+                }
+                CharacterRange range = ranges[first_range];
+                jschar from = range.from();
+                jschar to = range.to();
+                if (to > char_mask) {
+                    to = char_mask;
+                }
+                uint32_t differing_bits = (from ^ to);
+                // A mask and compare is only perfect if the differing bits form a
+                // number like 00011111 with one single block of trailing 1s.
+                if ((differing_bits & (differing_bits + 1)) == 0 &&
+                    from + differing_bits == to) {
+                    pos->determines_perfectly = true;
+                }
+                uint32_t common_bits = ~SmearBitsRight(differing_bits);
+                uint32_t bits = (from & common_bits);
+                for (size_t i = first_range + 1; i < ranges.length(); i++) {
+                    CharacterRange range = ranges[i];
+                    jschar from = range.from();
+                    jschar to = range.to();
+                    if (from > char_mask) continue;
+                    if (to > char_mask) to = char_mask;
+                    // Here we are combining more ranges into the mask and compare
+                    // value.  With each new range the mask becomes more sparse and
+                    // so the chances of a false positive rise.  A character class
+                    // with multiple ranges is assumed never to be equivalent to a
+                    // mask and compare operation.
+                    pos->determines_perfectly = false;
+                    uint32_t new_common_bits = (from ^ to);
+                    new_common_bits = ~SmearBitsRight(new_common_bits);
+                    common_bits &= new_common_bits;
+                    bits &= new_common_bits;
+                    uint32_t differing_bits = (from & common_bits) ^ bits;
+                    common_bits ^= differing_bits;
+                    bits &= common_bits;
+                }
+                pos->mask = common_bits;
+                pos->value = bits;
+            }
+            characters_filled_in++;
+            JS_ASSERT(characters_filled_in <= details->characters());
+            if (characters_filled_in == details->characters()) {
+                return;
+            }
+        }
+    }
+    JS_ASSERT(characters_filled_in != details->characters());
+    if (!details->cannot_match()) {
+        on_success()-> GetQuickCheckDetails(details,
+                                            compiler,
+                                            characters_filled_in,
+                                            true);
+    }
+}
+
+void
+QuickCheckDetails::Clear()
+{
+    for (int i = 0; i < characters_; i++) {
+        positions_[i].mask = 0;
+        positions_[i].value = 0;
+        positions_[i].determines_perfectly = false;
+    }
+    characters_ = 0;
+}
+
+void
+QuickCheckDetails::Advance(int by, bool ascii)
+{
+    JS_ASSERT(by >= 0);
+    if (by >= characters_) {
+        Clear();
+        return;
+    }
+    for (int i = 0; i < characters_ - by; i++) {
+        positions_[i] = positions_[by + i];
+    }
+    for (int i = characters_ - by; i < characters_; i++) {
+        positions_[i].mask = 0;
+        positions_[i].value = 0;
+        positions_[i].determines_perfectly = false;
+    }
+    characters_ -= by;
+    // We could change mask_ and value_ here but we would never advance unless
+    // they had already been used in a check and they won't be used again because
+    // it would gain us nothing.  So there's no point.
+}
+
+bool
+QuickCheckDetails::Rationalize(bool is_ascii)
+{
+    bool found_useful_op = false;
+    uint32_t char_mask = MaximumCharacter(is_ascii);
+
+    mask_ = 0;
+    value_ = 0;
+    int char_shift = 0;
+    for (int i = 0; i < characters_; i++) {
+        Position* pos = &positions_[i];
+        if ((pos->mask & kMaxOneByteCharCode) != 0)
+            found_useful_op = true;
+        mask_ |= (pos->mask & char_mask) << char_shift;
+        value_ |= (pos->value & char_mask) << char_shift;
+        char_shift += is_ascii ? 8 : 16;
+    }
+    return found_useful_op;
+}
+
+void QuickCheckDetails::Merge(QuickCheckDetails* other, int from_index)
+{
+    JS_ASSERT(characters_ == other->characters_);
+    if (other->cannot_match_)
+        return;
+    if (cannot_match_) {
+        *this = *other;
+        return;
+    }
+    for (int i = from_index; i < characters_; i++) {
+        QuickCheckDetails::Position* pos = positions(i);
+        QuickCheckDetails::Position* other_pos = other->positions(i);
+        if (pos->mask != other_pos->mask ||
+            pos->value != other_pos->value ||
+            !other_pos->determines_perfectly) {
+            // Our mask-compare operation will be approximate unless we have the
+            // exact same operation on both sides of the alternation.
+            pos->determines_perfectly = false;
+        }
+        pos->mask &= other_pos->mask;
+        pos->value &= pos->mask;
+        other_pos->value &= pos->mask;
+        jschar differing_bits = (pos->value ^ other_pos->value);
+        pos->mask &= ~differing_bits;
+        pos->value &= pos->mask;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/js/src/irregexp/RegExpEngine.h
@@ -0,0 +1,1518 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99: */
+
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_JSREGEXP_H_
+#define V8_JSREGEXP_H_
+
+#include "jscntxt.h"
+
+#include "ds/SplayTree.h"
+#include "jit/Label.h"
+#include "vm/RegExpObject.h"
+
+namespace js {
+
+class MatchPairs;
+class RegExpShared;
+
+namespace jit {
+    class Label;
+    class JitCode;
+}
+
+namespace irregexp {
+
+class RegExpTree;
+class RegExpMacroAssembler;
+
+struct RegExpCompileData
+{
+    RegExpCompileData()
+      : tree(nullptr),
+        simple(true),
+        contains_anchor(false),
+        capture_count(0)
+    {}
+
+    RegExpTree *tree;
+    bool simple;
+    bool contains_anchor;
+    int capture_count;
+};
+
+struct RegExpCode
+{
+#ifdef JS_ION
+    jit::JitCode *jitCode;
+    uint8_t *byteCode;
+
+    RegExpCode()
+      : jitCode(nullptr), byteCode(nullptr)
+    {}
+
+    bool empty() {
+        return !jitCode && !byteCode;
+    }
+
+    void destroy() {
+        js_free(byteCode);
+    }
+#else
+    uint8_t *byteCode;
+
+    RegExpCode()
+      : byteCode(nullptr)
+    {}
+
+    bool empty() {
+        return !byteCode;
+    }
+
+    void destroy() {
+        js_free(byteCode);
+    }
+#endif
+};
+
+RegExpCode
+CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData *data,
+               const jschar *sampleChars, size_t sampleLength,
+               bool is_global, bool ignore_case = false, bool is_ascii = false);
+
+// Note: this may return RegExpRunStatus_Error if an interrupt was requested
+// while the code was executing.
+RegExpRunStatus
+ExecuteCode(JSContext *cx, jit::JitCode *codeBlock,
+            const jschar *chars, size_t start, size_t length, MatchPairs *matches);
+
+RegExpRunStatus
+InterpretCode(JSContext *cx, const uint8_t *byteCode,
+              const jschar *chars, size_t start, size_t length, MatchPairs *matches);
+
+#define FOR_EACH_NODE_TYPE(VISIT)                                    \
+  VISIT(End)                                                         \
+  VISIT(Action)                                                      \
+  VISIT(Choice)                                                      \
+  VISIT(BackReference)                                               \
+  VISIT(Assertion)                                                   \
+  VISIT(Text)
+
+#define FOR_EACH_REG_EXP_TREE_TYPE(VISIT)                            \
+  VISIT(Disjunction)                                                 \
+  VISIT(Alternative)                                                 \
+  VISIT(Assertion)                                                   \
+  VISIT(CharacterClass)                                              \
+  VISIT(Atom)                                                        \
+  VISIT(Quantifier)                                                  \
+  VISIT(Capture)                                                     \
+  VISIT(Lookahead)                                                   \
+  VISIT(BackReference)                                               \
+  VISIT(Empty)                                                       \
+  VISIT(Text)
+
+#define FORWARD_DECLARE(Name) class RegExp##Name;
+FOR_EACH_REG_EXP_TREE_TYPE(FORWARD_DECLARE)
+#undef FORWARD_DECLARE
+
+class CharacterRange;
+typedef Vector<CharacterRange, 1, LifoAllocPolicy<Infallible> > CharacterRangeVector;
+
+// Represents code units in the range from from_ to to_, both ends are
+// inclusive.
+class CharacterRange
+{
+  public:
+    CharacterRange()
+      : from_(0), to_(0)
+    {}
+
+    CharacterRange(jschar from, jschar to)
+      : from_(from), to_(to)
+    {}
+
+    static void AddClassEscape(LifoAlloc *alloc, jschar type, CharacterRangeVector *ranges);
+
+    static inline CharacterRange Singleton(jschar value) {
+        return CharacterRange(value, value);
+    }
+    static inline CharacterRange Range(jschar from, jschar to) {
+        JS_ASSERT(from <= to);
+        return CharacterRange(from, to);
+    }
+    static inline CharacterRange Everything() {
+        return CharacterRange(0, 0xFFFF);
+    }
+    bool Contains(jschar i) { return from_ <= i && i <= to_; }
+    jschar from() const { return from_; }
+    void set_from(jschar value) { from_ = value; }
+    jschar to() const { return to_; }
+    void set_to(jschar value) { to_ = value; }
+    bool is_valid() { return from_ <= to_; }
+    bool IsEverything(jschar max) { return from_ == 0 && to_ >= max; }
+    bool IsSingleton() { return (from_ == to_); }
+    void AddCaseEquivalents(bool is_ascii, CharacterRangeVector *ranges);
+
+    static void Split(const LifoAlloc *alloc,
+                      CharacterRangeVector base,
+                      const Vector<int> &overlay,
+                      CharacterRangeVector* included,
+                      CharacterRangeVector* excluded);
+
+    // Whether a range list is in canonical form: Ranges ordered by from value,
+    // and ranges non-overlapping and non-adjacent.
+    static bool IsCanonical(const CharacterRangeVector &ranges);
+
+    // Convert range list to canonical form. The characters covered by the ranges
+    // will still be the same, but no character is in more than one range, and
+    // adjacent ranges are merged. The resulting list may be shorter than the
+    // original, but cannot be longer.
+    static void Canonicalize(CharacterRangeVector &ranges);
+
+    // Negate the contents of a character range in canonical form.
+    static void Negate(const LifoAlloc *alloc,
+                       CharacterRangeVector src,
+                       CharacterRangeVector *dst);
+
+    static const int kStartMarker = (1 << 24);
+    static const int kPayloadMask = (1 << 24) - 1;
+
+  private:
+    jschar from_;
+    jschar to_;
+};
+
+// A set of unsigned integers that behaves especially well on small
+// integers (< 32).
+class OutSet
+{
+  public:
+    OutSet()
+      : first_(0), remaining_(nullptr), successors_(nullptr)
+    {}
+
+    OutSet* Extend(LifoAlloc *alloc, unsigned value);
+    bool Get(unsigned value);
+    static const unsigned kFirstLimit = 32;
+
+  private:
+    typedef Vector<OutSet *, 1, LifoAllocPolicy<Infallible> > OutSetVector;
+    typedef Vector<unsigned, 1, LifoAllocPolicy<Infallible> > RemainingVector;
+
+    // Destructively set a value in this set.  In most cases you want
+    // to use Extend instead to ensure that only one instance exists
+    // that contains the same values.
+    void Set(LifoAlloc *alloc, unsigned value);
+
+    // The successors are a list of sets that contain the same values
+    // as this set and the one more value that is not present in this
+    // set.
+    OutSetVector *successors() { return successors_; }
+
+    OutSet(uint32_t first, RemainingVector *remaining)
+      : first_(first), remaining_(remaining), successors_(nullptr)
+    {}
+
+    RemainingVector &remaining() { return *remaining_; }
+
+    uint32_t first_;
+    RemainingVector *remaining_;
+    OutSetVector *successors_;
+    friend class Trace;
+};
+
+// A mapping from integers, specified as ranges, to a set of integers.
+// Used for mapping character ranges to choices.
+class DispatchTable
+{
+  public:
+    explicit DispatchTable(LifoAlloc *alloc)
+    {}
+
+    class Entry {
+      public:
+        Entry()
+          : from_(0), to_(0), out_set_(nullptr)
+        {}
+
+        Entry(jschar from, jschar to, OutSet* out_set)
+          : from_(from), to_(to), out_set_(out_set)
+        {}
+
+        jschar from() { return from_; }
+        jschar to() { return to_; }
+        void set_to(jschar value) { to_ = value; }
+        void AddValue(LifoAlloc *alloc, int value) {
+            out_set_ = out_set_->Extend(alloc, value);
+        }
+        OutSet* out_set() { return out_set_; }
+      private:
+        jschar from_;
+        jschar to_;
+        OutSet* out_set_;
+    };
+
+    void AddRange(LifoAlloc *alloc, CharacterRange range, int value);
+    OutSet* Get(jschar value);
+    void Dump();
+
+  private:
+    // There can't be a static empty set since it allocates its
+    // successors in a LifoAlloc and caches them.
+    OutSet* empty() { return &empty_; }
+    OutSet empty_;
+};
+
+class TextElement
+{
+  public:
+    enum TextType {
+        ATOM,
+        CHAR_CLASS
+    };
+
+    static TextElement Atom(RegExpAtom* atom);
+    static TextElement CharClass(RegExpCharacterClass* char_class);
+
+    int cp_offset() const { return cp_offset_; }
+    void set_cp_offset(int cp_offset) { cp_offset_ = cp_offset; }
+    int length() const;
+
+    TextType text_type() const { return text_type_; }
+
+    RegExpTree* tree() const { return tree_; }
+
+    RegExpAtom* atom() const {
+        JS_ASSERT(text_type() == ATOM);
+        return reinterpret_cast<RegExpAtom*>(tree());
+    }
+
+    RegExpCharacterClass* char_class() const {
+        JS_ASSERT(text_type() == CHAR_CLASS);
+        return reinterpret_cast<RegExpCharacterClass*>(tree());
+    }
+
+  private:
+    TextElement(TextType text_type, RegExpTree* tree)
+      : cp_offset_(-1), text_type_(text_type), tree_(tree)
+    {}
+
+    int cp_offset_;
+    TextType text_type_;
+    RegExpTree* tree_;
+};
+
+typedef Vector<TextElement, 1, LifoAllocPolicy<Infallible> > TextElementVector;
+
+class NodeVisitor;
+class RegExpCompiler;
+class Trace;
+class BoyerMooreLookahead;
+
+struct NodeInfo
+{
+    NodeInfo()
+      : being_analyzed(false),
+        been_analyzed(false),
+        follows_word_interest(false),
+        follows_newline_interest(false),
+        follows_start_interest(false),
+        at_end(false),
+        visited(false),
+        replacement_calculated(false)
+    {}
+
+    // Returns true if the interests and assumptions of this node
+    // matches the given one.
+    bool Matches(NodeInfo* that) {
+        return (at_end == that->at_end) &&
+            (follows_word_interest == that->follows_word_interest) &&
+            (follows_newline_interest == that->follows_newline_interest) &&
+            (follows_start_interest == that->follows_start_interest);
+    }
+
+    // Updates the interests of this node given the interests of the
+    // node preceding it.
+    void AddFromPreceding(NodeInfo* that) {
+        at_end |= that->at_end;
+        follows_word_interest |= that->follows_word_interest;
+        follows_newline_interest |= that->follows_newline_interest;
+        follows_start_interest |= that->follows_start_interest;
+    }
+
+    bool HasLookbehind() {
+        return follows_word_interest ||
+            follows_newline_interest ||
+            follows_start_interest;
+    }
+
+    // Sets the interests of this node to include the interests of the
+    // following node.
+    void AddFromFollowing(NodeInfo* that) {
+        follows_word_interest |= that->follows_word_interest;
+        follows_newline_interest |= that->follows_newline_interest;
+        follows_start_interest |= that->follows_start_interest;
+    }
+
+    void ResetCompilationState() {
+        being_analyzed = false;
+        been_analyzed = false;
+    }
+
+    bool being_analyzed: 1;
+    bool been_analyzed: 1;
+
+    // These bits are set of this node has to know what the preceding
+    // character was.
+    bool follows_word_interest: 1;
+    bool follows_newline_interest: 1;
+    bool follows_start_interest: 1;
+
+    bool at_end: 1;
+    bool visited: 1;
+    bool replacement_calculated: 1;
+};
+
+// Details of a quick mask-compare check that can look ahead in the
+// input stream.
+class QuickCheckDetails
+{
+  public:
+    QuickCheckDetails()
+      : characters_(0),
+        mask_(0),
+        value_(0),
+        cannot_match_(false)
+    {}
+
+    explicit QuickCheckDetails(int characters)
+      : characters_(characters),
+        mask_(0),
+        value_(0),
+        cannot_match_(false)
+    {}
+
+    bool Rationalize(bool ascii);
+
+    // Merge in the information from another branch of an alternation.
+    void Merge(QuickCheckDetails* other, int from_index);
+
+    // Advance the current position by some amount.
+    void Advance(int by, bool ascii);
+
+    void Clear();
+
+    bool cannot_match() { return cannot_match_; }
+    void set_cannot_match() { cannot_match_ = true; }
+
+    int characters() { return characters_; }
+    void set_characters(int characters) { characters_ = characters; }
+
+    struct Position {
+        Position() : mask(0), value(0), determines_perfectly(false) { }
+        jschar mask;
+        jschar value;
+        bool determines_perfectly;
+    };
+
+    Position* positions(int index) {
+        JS_ASSERT(index >= 0);
+        JS_ASSERT(index < characters_);
+        return positions_ + index;
+    }
+
+    uint32_t mask() { return mask_; }
+    uint32_t value() { return value_; }
+
+  private:
+    // How many characters do we have quick check information from.  This is
+    // the same for all branches of a choice node.
+    int characters_;
+    Position positions_[4];
+
+    // These values are the condensate of the above array after Rationalize().
+    uint32_t mask_;
+    uint32_t value_;
+
+    // If set to true, there is no way this quick check can match at all.
+    // E.g., if it requires to be at the start of the input, and isn't.
+    bool cannot_match_;
+};
+
+class RegExpNode
+{
+  public:
+    explicit RegExpNode(LifoAlloc *alloc);
+    virtual ~RegExpNode() {}
+    virtual void Accept(NodeVisitor* visitor) = 0;
+
+    // Generates a goto to this node or actually generates the code at this point.
+    virtual void Emit(RegExpCompiler* compiler, Trace* trace) = 0;
+
+    // How many characters must this node consume at a minimum in order to
+    // succeed.  If we have found at least 'still_to_find' characters that
+    // must be consumed there is no need to ask any following nodes whether
+    // they are sure to eat any more characters.  The not_at_start argument is
+    // used to indicate that we know we are not at the start of the input.  In
+    // this case anchored branches will always fail and can be ignored when
+    // determining how many characters are consumed on success.
+    virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start) = 0;
+
+    // Emits some quick code that checks whether the preloaded characters match.
+    // Falls through on certain failure, jumps to the label on possible success.
+    // If the node cannot make a quick check it does nothing and returns false.
+    bool EmitQuickCheck(RegExpCompiler* compiler,
+                        Trace* trace,
+                        bool preload_has_checked_bounds,
+                        jit::Label* on_possible_success,
+                        QuickCheckDetails* details_return,
+                        bool fall_through_on_failure);
+
+    // For a given number of characters this returns a mask and a value.  The
+    // next n characters are anded with the mask and compared with the value.
+    // A comparison failure indicates the node cannot match the next n characters.
+    // A comparison success indicates the node may match.
+    virtual void GetQuickCheckDetails(QuickCheckDetails* details,
+                                      RegExpCompiler* compiler,
+                                      int characters_filled_in,
+                                      bool not_at_start) = 0;
+
+    static const int kNodeIsTooComplexForGreedyLoops = -1;
+
+    virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; }
+
+    // Only returns the successor for a text node of length 1 that matches any
+    // character and that has no guards on it.
+    virtual RegExpNode* GetSuccessorOfOmnivorousTextNode(RegExpCompiler* compiler) {
+        return nullptr;
+    }
+
+    static const int kRecursionBudget = 200;
+
+    // Collects information on the possible code units (mod 128) that can match if
+    // we look forward.  This is used for a Boyer-Moore-like string searching
+    // implementation.  TODO(erikcorry):  This should share more code with
+    // EatsAtLeast, GetQuickCheckDetails.  The budget argument is used to limit
+    // the number of nodes we are willing to look at in order to create this data.
+    virtual void FillInBMInfo(int offset,
+                              int budget,
+                              BoyerMooreLookahead* bm,
+                              bool not_at_start) {
+        MOZ_ASSUME_UNREACHABLE("Bad call");
+    }
+
+    // If we know that the input is ASCII then there are some nodes that can
+    // never match.  This method returns a node that can be substituted for
+    // itself, or nullptr if the node can never match.
+    virtual RegExpNode* FilterASCII(int depth, bool ignore_case) { return this; }
+
+    // Helper for FilterASCII.
+    RegExpNode* replacement() {
+        JS_ASSERT(info()->replacement_calculated);
+        return replacement_;
+    }
+    RegExpNode* set_replacement(RegExpNode* replacement) {
+        info()->replacement_calculated = true;
+        replacement_ =  replacement;
+        return replacement;  // For convenience.
+    }
+
+    // We want to avoid recalculating the lookahead info, so we store it on the
+    // node.  Only info that is for this node is stored.  We can tell that the
+    // info is for this node when offset == 0, so the information is calculated
+    // relative to this node.
+    void SaveBMInfo(BoyerMooreLookahead* bm, bool not_at_start, int offset) {
+        if (offset == 0) set_bm_info(not_at_start, bm);
+    }
+
+    jit::Label* label() { return &label_; }
+
+    // If non-generic code is generated for a node (i.e. the node is not at the
+    // start of the trace) then it cannot be reused.  This variable sets a limit
+    // on how often we allow that to happen before we insist on starting a new
+    // trace and generating generic code for a node that can be reused by flushing
+    // the deferred actions in the current trace and generating a goto.
+    static const int kMaxCopiesCodeGenerated = 10;
+
+    NodeInfo* info() { return &info_; }
+
+    BoyerMooreLookahead* bm_info(bool not_at_start) {
+        return bm_info_[not_at_start ? 1 : 0];
+    }
+
+    LifoAlloc *alloc() const { return alloc_; }
+
+  protected:
+    enum LimitResult { DONE, CONTINUE };
+    RegExpNode* replacement_;
+
+    LimitResult LimitVersions(RegExpCompiler* compiler, Trace* trace);
+
+    void set_bm_info(bool not_at_start, BoyerMooreLookahead* bm) {
+        bm_info_[not_at_start ? 1 : 0] = bm;
+    }
+
+  private:
+    static const int kFirstCharBudget = 10;
+    jit::Label label_;
+    NodeInfo info_;
+
+    // This variable keeps track of how many times code has been generated for
+    // this node (in different traces).  We don't keep track of where the
+    // generated code is located unless the code is generated at the start of
+    // a trace, in which case it is generic and can be reused by flushing the
+    // deferred operations in the current trace and generating a goto.
+    int trace_count_;
+    BoyerMooreLookahead* bm_info_[2];
+
+    LifoAlloc *alloc_;
+};
+
+// A simple closed interval.
+class Interval
+{
+  public:
+    Interval() : from_(kNone), to_(kNone) { }
+
+    Interval(int from, int to) : from_(from), to_(to) { }
+
+    Interval Union(Interval that) {
+        if (that.from_ == kNone)
+            return *this;
+        else if (from_ == kNone)
+            return that;
+        else
+            return Interval(Min(from_, that.from_), Max(to_, that.to_));
+    }
+
+    bool Contains(int value) {
+        return (from_ <= value) && (value <= to_);
+    }
+
+    bool is_empty() { return from_ == kNone; }
+
+    int from() const { return from_; }
+    int to() const { return to_; }
+
+    static Interval Empty() { return Interval(); }
+    static const int kNone = -1;
+
+  private:
+    int from_;
+    int to_;
+};
+
+class SeqRegExpNode : public RegExpNode
+{
+  public:
+    explicit SeqRegExpNode(RegExpNode* on_success)
+      : RegExpNode(on_success->alloc()), on_success_(on_success)
+    {}
+
+    RegExpNode* on_success() { return on_success_; }
+    void set_on_success(RegExpNode* node) { on_success_ = node; }
+    virtual RegExpNode* FilterASCII(int depth, bool ignore_case);
+    virtual void FillInBMInfo(int offset,
+                              int budget,
+                              BoyerMooreLookahead* bm,
+                              bool not_at_start) {
+        on_success_->FillInBMInfo(offset, budget - 1, bm, not_at_start);
+        if (offset == 0) set_bm_info(not_at_start, bm);
+    }
+
+  protected:
+    RegExpNode* FilterSuccessor(int depth, bool ignore_case);
+
+  private:
+    RegExpNode* on_success_;
+};
+
+class ActionNode : public SeqRegExpNode
+{
+  public:
+    enum ActionType {
+        SET_REGISTER,
+        INCREMENT_REGISTER,
+        STORE_POSITION,
+        BEGIN_SUBMATCH,
+        POSITIVE_SUBMATCH_SUCCESS,
+        EMPTY_MATCH_CHECK,
+        CLEAR_CAPTURES
+    };
+
+    ActionNode(ActionType action_type, RegExpNode* on_success)
+      : SeqRegExpNode(on_success),
+        action_type_(action_type)
+    {}
+
+    static ActionNode* SetRegister(int reg, int val, RegExpNode* on_success);
+    static ActionNode* IncrementRegister(int reg, RegExpNode* on_success);
+    static ActionNode* StorePosition(int reg,
+                                     bool is_capture,
+                                     RegExpNode* on_success);
+    static ActionNode* ClearCaptures(Interval range, 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,
+                                               int clear_capture_count,
+                                               int clear_capture_from,
+                                               RegExpNode* on_success);
+    static ActionNode* EmptyMatchCheck(int start_register,
+                                       int repetition_register,
+                                       int repetition_limit,
+                                       RegExpNode* on_success);
+    virtual void Accept(NodeVisitor* visitor);
+    virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+    virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
+    virtual void GetQuickCheckDetails(QuickCheckDetails* details,
+                                      RegExpCompiler* compiler,
+                                      int filled_in,
+                                      bool not_at_start) {
+        return on_success()->GetQuickCheckDetails(
+                                                  details, compiler, filled_in, not_at_start);
+    }
+    virtual void FillInBMInfo(int offset,
+                              int budget,
+                              BoyerMooreLookahead* bm,
+                              bool not_at_start);
+    ActionType action_type() { return action_type_; }
+    // TODO(erikcorry): We should allow some action nodes in greedy loops.
+    virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; }
+
+  private:
+    union {
+        struct {
+            int reg;
+            int value;
+        } u_store_register;
+        struct {
+            int reg;
+        } u_increment_register;
+        struct {
+            int reg;
+            bool is_capture;
+        } u_position_register;
+        struct {
+            int stack_pointer_register;
+            int current_position_register;
+            int clear_register_count;
+            int clear_register_from;
+        } u_submatch;
+        struct {
+            int start_register;
+            int repetition_register;
+            int repetition_limit;
+        } u_empty_match_check;
+        struct {
+            int range_from;
+            int range_to;
+        } u_clear_captures;
+    } data_;
+    ActionType action_type_;
+    friend class DotPrinter;
+};
+
+class TextNode : public SeqRegExpNode
+{
+  public:
+    TextNode(TextElementVector *elements,
+             RegExpNode *on_success)
+      : SeqRegExpNode(on_success),
+        elements_(elements)
+    {}
+
+    TextNode(RegExpCharacterClass* that,
+             RegExpNode* on_success)
+      : SeqRegExpNode(on_success),
+        elements_(alloc()->newInfallible<TextElementVector>(*alloc()))
+    {
+        elements_->append(TextElement::CharClass(that));
+    }
+
+    virtual void Accept(NodeVisitor* visitor);
+    virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+    virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
+    virtual void GetQuickCheckDetails(QuickCheckDetails* details,
+                                      RegExpCompiler* compiler,
+                                      int characters_filled_in,
+                                      bool not_at_start);
+    TextElementVector &elements() { return *elements_; }
+    void MakeCaseIndependent(bool is_ascii);
+    virtual int GreedyLoopTextLength();
+    virtual RegExpNode* GetSuccessorOfOmnivorousTextNode(
+                                                         RegExpCompiler* compiler);
+    virtual void FillInBMInfo(int offset,
+                              int budget,
+                              BoyerMooreLookahead* bm,
+                              bool not_at_start);
+    void CalculateOffsets();
+    virtual RegExpNode* FilterASCII(int depth, bool ignore_case);
+
+  private:
+    enum TextEmitPassType {
+        NON_ASCII_MATCH,             // Check for characters that can't match.
+        SIMPLE_CHARACTER_MATCH,      // Case-dependent single character check.
+        NON_LETTER_CHARACTER_MATCH,  // Check characters that have no case equivs.
+        CASE_CHARACTER_MATCH,        // Case-independent single character check.
+        CHARACTER_CLASS_MATCH        // Character class.
+    };
+    static bool SkipPass(int pass, bool ignore_case);
+    static const int kFirstRealPass = SIMPLE_CHARACTER_MATCH;
+    static const int kLastPass = CHARACTER_CLASS_MATCH;
+    void TextEmitPass(RegExpCompiler* compiler,
+                      TextEmitPassType pass,
+                      bool preloaded,
+                      Trace* trace,
+                      bool first_element_checked,
+                      int* checked_up_to);
+    int Length();
+    TextElementVector *elements_;
+};
+
+class AssertionNode : public SeqRegExpNode
+{
+  public:
+    enum AssertionType {
+        AT_END,
+        AT_START,
+        AT_BOUNDARY,
+        AT_NON_BOUNDARY,
+        AFTER_NEWLINE
+    };
+    AssertionNode(AssertionType t, RegExpNode* on_success)
+      : SeqRegExpNode(on_success), assertion_type_(t)
+    {}
+
+    static AssertionNode* AtEnd(RegExpNode* on_success) {
+        return on_success->alloc()->newInfallible<AssertionNode>(AT_END, on_success);
+    }
+    static AssertionNode* AtStart(RegExpNode* on_success) {
+        return on_success->alloc()->newInfallible<AssertionNode>(AT_START, on_success);
+    }
+    static AssertionNode* AtBoundary(RegExpNode* on_success) {
+        return on_success->alloc()->newInfallible<AssertionNode>(AT_BOUNDARY, on_success);
+    }
+    static AssertionNode* AtNonBoundary(RegExpNode* on_success) {
+        return on_success->alloc()->newInfallible<AssertionNode>(AT_NON_BOUNDARY, on_success);
+    }
+    static AssertionNode* AfterNewline(RegExpNode* on_success) {
+        return on_success->alloc()->newInfallible<AssertionNode>(AFTER_NEWLINE, on_success);
+    }
+    virtual void Accept(NodeVisitor* visitor);
+    virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+    virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
+    virtual void GetQuickCheckDetails(QuickCheckDetails* details,
+                                      RegExpCompiler* compiler,
+                                      int filled_in,
+                                      bool not_at_start);
+    virtual void FillInBMInfo(int offset,
+                              int budget,
+                              BoyerMooreLookahead* bm,
+                              bool not_at_start);
+    AssertionType assertion_type() { return assertion_type_; }
+
+  private:
+    void EmitBoundaryCheck(RegExpCompiler* compiler, Trace* trace);
+    enum IfPrevious { kIsNonWord, kIsWord };
+    void BacktrackIfPrevious(RegExpCompiler* compiler,
+                             Trace* trace,
+                             IfPrevious backtrack_if_previous);
+    AssertionType assertion_type_;
+};
+
+class BackReferenceNode : public SeqRegExpNode
+{
+  public:
+    BackReferenceNode(int start_reg,
+                      int end_reg,
+                      RegExpNode* on_success)
+      : SeqRegExpNode(on_success),
+        start_reg_(start_reg),
+        end_reg_(end_reg)
+    {}
+
+    virtual void Accept(NodeVisitor* visitor);
+    int start_register() { return start_reg_; }
+    int end_register() { return end_reg_; }
+    virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+    virtual int EatsAtLeast(int still_to_find,
+                            int recursion_depth,
+                            bool not_at_start);
+    virtual void GetQuickCheckDetails(QuickCheckDetails* details,
+                                      RegExpCompiler* compiler,
+                                      int characters_filled_in,
+                                      bool not_at_start) {
+        return;
+    }
+    virtual void FillInBMInfo(int offset,
+                              int budget,
+                              BoyerMooreLookahead* bm,
+                              bool not_at_start);
+
+  private:
+    int start_reg_;
+    int end_reg_;
+};
+
+class EndNode : public RegExpNode
+{
+  public:
+    enum Action { ACCEPT, BACKTRACK, NEGATIVE_SUBMATCH_SUCCESS };
+
+    explicit EndNode(LifoAlloc *alloc, Action action)
+      : RegExpNode(alloc), action_(action)
+    {}
+
+    virtual void Accept(NodeVisitor* visitor);
+    virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+    virtual int EatsAtLeast(int still_to_find,
+                            int recursion_depth,
+                            bool not_at_start) { return 0; }
+    virtual void GetQuickCheckDetails(QuickCheckDetails* details,
+                                      RegExpCompiler* compiler,
+                                      int characters_filled_in,
+                                      bool not_at_start)
+    {
+        // Returning 0 from EatsAtLeast should ensure we never get here.
+        MOZ_ASSUME_UNREACHABLE("Bad call");
+    }
+    virtual void FillInBMInfo(int offset,
+                              int budget,
+                              BoyerMooreLookahead* bm,
+                              bool not_at_start) {
+        // Returning 0 from EatsAtLeast should ensure we never get here.
+        MOZ_ASSUME_UNREACHABLE("Bad call");
+    }
+
+  private:
+    Action action_;
+};
+
+class NegativeSubmatchSuccess : public EndNode
+{
+  public:
+    NegativeSubmatchSuccess(LifoAlloc *alloc,
+                            int stack_pointer_reg,
+                            int position_reg,
+                            int clear_capture_count,
+                            int clear_capture_start)
+      : EndNode(alloc, NEGATIVE_SUBMATCH_SUCCESS),
+        stack_pointer_register_(stack_pointer_reg),
+        current_position_register_(position_reg),
+        clear_capture_count_(clear_capture_count),
+        clear_capture_start_(clear_capture_start)
+    {}
+
+    virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+
+  private:
+    int stack_pointer_register_;
+    int current_position_register_;
+    int clear_capture_count_;
+    int clear_capture_start_;
+};
+
+class Guard
+{
+  public:
+    enum Relation { LT, GEQ };
+    Guard(int reg, Relation op, int value)
+        : reg_(reg),
+          op_(op),
+          value_(value)
+    {}
+
+    int reg() { return reg_; }
+    Relation op() { return op_; }
+    int value() { return value_; }
+
+  private:
+    int reg_;
+    Relation op_;
+    int value_;
+};
+
+typedef Vector<Guard *, 1, LifoAllocPolicy<Infallible> > GuardVector;
+
+class GuardedAlternative
+{
+  public:
+    explicit GuardedAlternative(RegExpNode* node)
+      : node_(node), guards_(nullptr)
+    {}
+
+    void AddGuard(LifoAlloc *alloc, Guard *guard);
+    RegExpNode *node() const { return node_; }
+    void set_node(RegExpNode* node) { node_ = node; }
+    const GuardVector *guards() const { return guards_; }
+
+  private:
+    RegExpNode *node_;
+    GuardVector *guards_;
+};
+
+typedef Vector<GuardedAlternative, 0, LifoAllocPolicy<Infallible> > GuardedAlternativeVector;
+
+class AlternativeGeneration;
+
+class ChoiceNode : public RegExpNode
+{
+  public:
+    explicit ChoiceNode(LifoAlloc *alloc, int expected_size)
+      : RegExpNode(alloc),
+        alternatives_(*alloc),
+        table_(nullptr),
+        not_at_start_(false),
+        being_calculated_(false)
+    {
+        alternatives_.reserve(expected_size);
+    }
+
+    virtual void Accept(NodeVisitor* visitor);
+    void AddAlternative(GuardedAlternative node) {
+        alternatives_.append(node);
+    }
+
+    GuardedAlternativeVector &alternatives() { return alternatives_; }
+    DispatchTable* GetTable(bool ignore_case);
+    virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+    virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
+    int EatsAtLeastHelper(int still_to_find,
+                          int budget,
+                          RegExpNode* ignore_this_node,
+                          bool not_at_start);
+    virtual void GetQuickCheckDetails(QuickCheckDetails* details,
+                                      RegExpCompiler* compiler,
+                                      int characters_filled_in,
+                                      bool not_at_start);
+    virtual void FillInBMInfo(int offset,
+                              int budget,
+                              BoyerMooreLookahead* bm,
+                              bool not_at_start);
+
+    bool being_calculated() { return being_calculated_; }
+    bool not_at_start() { return not_at_start_; }
+    void set_not_at_start() { not_at_start_ = true; }
+    void set_being_calculated(bool b) { being_calculated_ = b; }
+    virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; }
+    virtual RegExpNode* FilterASCII(int depth, bool ignore_case);
+
+  protected:
+    int GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative);
+    GuardedAlternativeVector alternatives_;
+
+  private:
+    friend class Analysis;
+    void GenerateGuard(RegExpMacroAssembler* macro_assembler,
+                       Guard* guard,
+                       Trace* trace);
+    int CalculatePreloadCharacters(RegExpCompiler* compiler, int eats_at_least);
+    void EmitOutOfLineContinuation(RegExpCompiler* compiler,
+                                   Trace* trace,
+                                   GuardedAlternative alternative,
+                                   AlternativeGeneration* alt_gen,
+                                   int preload_characters,
+                                   bool next_expects_preload);
+    DispatchTable* table_;
+
+    // If true, this node is never checked at the start of the input.
+    // Allows a new trace to start with at_start() set to false.
+    bool not_at_start_;
+    bool being_calculated_;
+};
+
+class NegativeLookaheadChoiceNode : public ChoiceNode
+{
+  public:
+    explicit NegativeLookaheadChoiceNode(LifoAlloc *alloc,
+                                         GuardedAlternative this_must_fail,
+                                         GuardedAlternative then_do_this)
+      : ChoiceNode(alloc, 2)
+    {
+        AddAlternative(this_must_fail);
+        AddAlternative(then_do_this);
+    }
+    virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
+    virtual void GetQuickCheckDetails(QuickCheckDetails* details,
+                                      RegExpCompiler* compiler,
+                                      int characters_filled_in,
+                                      bool not_at_start);
+    virtual void FillInBMInfo(int offset,
+                              int budget,
+                              BoyerMooreLookahead* bm,
+                              bool not_at_start)
+    {
+        alternatives()[1].node()->FillInBMInfo(offset, budget - 1, bm, not_at_start);
+        if (offset == 0)
+            set_bm_info(not_at_start, bm);
+    }
+
+    // For a negative lookahead we don't emit the quick check for the
+    // alternative that is expected to fail.  This is because quick check code
+    // starts by loading enough characters for the alternative that takes fewest
+    // characters, but on a negative lookahead the negative branch did not take
+    // part in that calculation (EatsAtLeast) so the assumptions don't hold.
+    virtual bool try_to_emit_quick_check_for_alternative(int i) { return i != 0; }
+    virtual RegExpNode* FilterASCII(int depth, bool ignore_case);
+};
+
+class LoopChoiceNode : public ChoiceNode
+{
+  public:
+    explicit LoopChoiceNode(LifoAlloc *alloc, bool body_can_be_zero_length)
+      : ChoiceNode(alloc, 2),
+        loop_node_(nullptr),
+        continue_node_(nullptr),
+        body_can_be_zero_length_(body_can_be_zero_length)
+    {}
+
+    void AddLoopAlternative(GuardedAlternative alt);
+    void AddContinueAlternative(GuardedAlternative alt);
+    virtual void Emit(RegExpCompiler* compiler, Trace* trace);
+    virtual int EatsAtLeast(int still_to_find,  int budget, bool not_at_start);
+    virtual void GetQuickCheckDetails(QuickCheckDetails* details,
+                                      RegExpCompiler* compiler,
+                                      int characters_filled_in,
+                                      bool not_at_start);
+    virtual void FillInBMInfo(int offset,
+                              int budget,
+                              BoyerMooreLookahead* bm,
+                              bool not_at_start);
+    RegExpNode* loop_node() { return loop_node_; }
+    RegExpNode* continue_node() { return continue_node_; }
+    bool body_can_be_zero_length() { return body_can_be_zero_length_; }
+    virtual void Accept(NodeVisitor* visitor);
+    virtual RegExpNode* FilterASCII(int depth, bool ignore_case);
+
+  private:
+    // AddAlternative is made private for loop nodes because alternatives
+    // should not be added freely, we need to keep track of which node
+    // goes back to the node itself.
+    void AddAlternative(GuardedAlternative node) {
+        ChoiceNode::AddAlternative(node);
+    }
+
+    RegExpNode* loop_node_;
+    RegExpNode* continue_node_;
+    bool body_can_be_zero_length_;
+};
+
+// Improve the speed that we scan for an initial point where a non-anchored
+// regexp can match by using a Boyer-Moore-like table. This is done by
+// identifying non-greedy non-capturing loops in the nodes that eat any
+// character one at a time.  For example in the middle of the regexp
+// /foo[\s\S]*?bar/ we find such a loop.  There is also such a loop implicitly
+// inserted at the start of any non-anchored regexp.
+//
+// When we have found such a loop we look ahead in the nodes to find the set of
+// characters that can come at given distances. For example for the regexp
+// /.?foo/ we know that there are at least 3 characters ahead of us, and the
+// sets of characters that can occur are [any, [f, o], [o]]. We find a range in
+// the lookahead info where the set of characters is reasonably constrained. In
+// our example this is from index 1 to 2 (0 is not constrained). We can now
+// look 3 characters ahead and if we don't find one of [f, o] (the union of
+// [f, o] and [o]) then we can skip forwards by the range size (in this case 2).
+//
+// For Unicode input strings we do the same, but modulo 128.
+//
+// We also look at the first string fed to the regexp and use that to get a hint
+// of the character frequencies in the inputs. This affects the assessment of
+// whether the set of characters is 'reasonably constrained'.
+//
+// We also have another lookahead mechanism (called quick check in the code),
+// which uses a wide load of multiple characters followed by a mask and compare
+// to determine whether a match is possible at this point.
+enum ContainedInLattice {
+  kNotYet = 0,
+  kLatticeIn = 1,
+  kLatticeOut = 2,
+  kLatticeUnknown = 3  // Can also mean both in and out.
+};
+
+inline ContainedInLattice
+Combine(ContainedInLattice a, ContainedInLattice b) {
+    return static_cast<ContainedInLattice>(a | b);
+}
+
+ContainedInLattice
+AddRange(ContainedInLattice a,
+         const int* ranges,
+         int ranges_size,
+         Interval new_range);
+
+class BoyerMoorePositionInfo
+{
+  public:
+    explicit BoyerMoorePositionInfo(LifoAlloc *alloc)
+      : map_(*alloc),
+        map_count_(0),
+        w_(kNotYet),
+        s_(kNotYet),
+        d_(kNotYet),
+        surrogate_(kNotYet)
+    {
+        map_.reserve(kMapSize);
+        for (int i = 0; i < kMapSize; i++)
+            map_.append(false);
+    }
+
+    bool& at(int i) { return map_[i]; }
+
+    static const int kMapSize = 128;
+    static const int kMask = kMapSize - 1;
+
+    int map_count() const { return map_count_; }
+
+    void Set(int character);
+    void SetInterval(const Interval& interval);
+    void SetAll();
+    bool is_non_word() { return w_ == kLatticeOut; }
+    bool is_word() { return w_ == kLatticeIn; }
+
+  private:
+    Vector<bool, 0, LifoAllocPolicy<Infallible> > map_;
+    int map_count_;  // Number of set bits in the map.
+    ContainedInLattice w_;  // The \w character class.
+    ContainedInLattice s_;  // The \s character class.
+    ContainedInLattice d_;  // The \d character class.
+    ContainedInLattice surrogate_;  // Surrogate UTF-16 code units.
+};
+
+typedef Vector<BoyerMoorePositionInfo *, 1, LifoAllocPolicy<Infallible> > BoyerMoorePositionInfoVector;
+
+class BoyerMooreLookahead
+{
+  public:
+    BoyerMooreLookahead(LifoAlloc *alloc, size_t length, RegExpCompiler* compiler);
+
+    int length() { return length_; }
+    int max_char() { return max_char_; }
+    RegExpCompiler* compiler() { return compiler_; }
+
+    int Count(int map_number) {
+        return bitmaps_[map_number]->map_count();
+    }
+
+    BoyerMoorePositionInfo* at(int i) { return bitmaps_[i]; }
+
+    void Set(int map_number, int character) {
+        if (character > max_char_) return;
+        BoyerMoorePositionInfo* info = bitmaps_[map_number];
+        info->Set(character);
+    }
+
+    void SetInterval(int map_number, const Interval& interval) {
+        if (interval.from() > max_char_) return;
+        BoyerMoorePositionInfo* info = bitmaps_[map_number];
+        if (interval.to() > max_char_) {
+            info->SetInterval(Interval(interval.from(), max_char_));
+        } else {
+            info->SetInterval(interval);
+        }
+    }
+
+    void SetAll(int map_number) {
+        bitmaps_[map_number]->SetAll();
+    }
+
+    void SetRest(int from_map) {
+        for (int i = from_map; i < length_; i++) SetAll(i);
+    }
+    bool EmitSkipInstructions(RegExpMacroAssembler* masm);
+
+  private:
+    // This is the value obtained by EatsAtLeast.  If we do not have at least this
+    // many characters left in the sample string then the match is bound to fail.
+    // Therefore it is OK to read a character this far ahead of the current match
+    // point.
+    int length_;
+    RegExpCompiler* compiler_;
+
+    // 0x7f for ASCII, 0xffff for UTF-16.
+    int max_char_;
+    BoyerMoorePositionInfoVector bitmaps_;
+
+    int GetSkipTable(int min_lookahead,
+                     int max_lookahead,
+                     uint8_t *boolean_skip_table);
+    bool FindWorthwhileInterval(int* from, int* to);
+    int FindBestInterval(int max_number_of_chars, int old_biggest_points, int* from, int* to);
+};
+
+// 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.  The effect of this is that we
+// generate code for paths that the matcher can take through the regular
+// expression.  A given node in the regexp can be code-generated several times
+// as it can be part of several traces.  For example for the regexp:
+// /foo(bar|ip)baz/ the code to match baz will be generated twice, once as part
+// of the foo-bar-baz trace and once as part of the foo-ip-baz trace.  The code
+// to match foo is generated only once (the traces have a common prefix).  The
+// code to store the capture is deferred and generated (twice) after the places
+// where baz has been matched.
+class Trace
+{
+  public:
+    // A value for a property that is either known to be true, know to be false,
+    // or not known.
+    enum TriBool {
+        UNKNOWN = -1, FALSE_VALUE = 0, TRUE_VALUE = 1
+    };
+
+    class DeferredAction {
+      public:
+        DeferredAction(ActionNode::ActionType action_type, int reg)
+          : action_type_(action_type), reg_(reg), next_(nullptr)
+        {}
+
+        DeferredAction* next() { return next_; }
+        bool Mentions(int reg);
+        int reg() { return reg_; }
+        ActionNode::ActionType action_type() { return action_type_; }
+      private:
+        ActionNode::ActionType action_type_;
+        int reg_;
+        DeferredAction* next_;
+        friend class Trace;
+    };
+
+    class DeferredCapture : public DeferredAction {
+      public:
+        DeferredCapture(int reg, bool is_capture, Trace* trace)
+          : DeferredAction(ActionNode::STORE_POSITION, reg),
+            cp_offset_(trace->cp_offset()),
+            is_capture_(is_capture)
+        {}
+
+        int cp_offset() { return cp_offset_; }
+        bool is_capture() { return is_capture_; }
+      private:
+        int cp_offset_;
+        bool is_capture_;
+        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 DeferredClearCaptures : public DeferredAction {
+      public:
+        explicit DeferredClearCaptures(Interval range)
+          : DeferredAction(ActionNode::CLEAR_CAPTURES, -1),
+            range_(range)
+        {}
+
+        Interval range() { return range_; }
+      private:
+        Interval range_;
+    };
+
+    class DeferredIncrementRegister : public DeferredAction {
+      public:
+        explicit DeferredIncrementRegister(int reg)
+          : DeferredAction(ActionNode::INCREMENT_REGISTER, reg)
+        {}
+    };
+
+    Trace()
+      : cp_offset_(0),
+        actions_(nullptr),
+        backtrack_(nullptr),
+        stop_node_(nullptr),
+        loop_label_(nullptr),
+        characters_preloaded_(0),
+        bound_checked_up_to_(0),
+        flush_budget_(100),
+        at_start_(UNKNOWN)
+    {}
+
+    // End the trace.  This involves flushing the deferred actions in the trace
+    // and pushing a backtrack location onto the backtrack stack.  Once this is
+    // done we can start a new trace or go to one that has already been
+    // generated.
+    void Flush(RegExpCompiler* compiler, RegExpNode* successor);
+
+    int cp_offset() { return cp_offset_; }
+    DeferredAction* actions() { return actions_; }
+
+    // A trivial trace is one that has no deferred actions or other state that
+    // affects the assumptions used when generating code.  There is no recorded
+    // backtrack location in a trivial trace, so with a trivial trace we will
+    // generate code that, on a failure to match, gets the backtrack location
+    // from the backtrack stack rather than using a direct jump instruction.  We
+    // always start code generation with a trivial trace and non-trivial traces
+    // are created as we emit code for nodes or add to the list of deferred
+    // actions in the trace.  The location of the code generated for a node using
+    // a trivial trace is recorded in a label in the node so that gotos can be
+    // generated to that code.
+    bool is_trivial() {
+        return backtrack_ == nullptr &&
+            actions_ == nullptr &&
+            cp_offset_ == 0 &&
+            characters_preloaded_ == 0 &&
+            bound_checked_up_to_ == 0 &&
+            quick_check_performed_.characters() == 0 &&
+            at_start_ == UNKNOWN;
+    }
+
+    TriBool at_start() { return at_start_; }
+    void set_at_start(bool at_start) {
+        at_start_ = at_start ? TRUE_VALUE : FALSE_VALUE;
+    }
+    jit::Label* backtrack() { return backtrack_; }
+    jit::Label* loop_label() { return loop_label_; }
+    RegExpNode* stop_node() { return stop_node_; }
+    int characters_preloaded() { return characters_preloaded_; }
+    int bound_checked_up_to() { return bound_checked_up_to_; }
+    int flush_budget() { return flush_budget_; }
+    QuickCheckDetails* quick_check_performed() { return &quick_check_performed_; }
+    bool mentions_reg(int reg);
+
+    // Returns true if a deferred position store exists to the specified
+    // register and stores the offset in the out-parameter.  Otherwise
+    // returns false.
+    bool GetStoredPosition(int reg, int* cp_offset);
+
+    // These set methods and AdvanceCurrentPositionInTrace should be used only on
+    // new traces - the intention is that traces are immutable after creation.
+    void add_action(DeferredAction* new_action) {
+        JS_ASSERT(new_action->next_ == nullptr);
+        new_action->next_ = actions_;
+        actions_ = new_action;
+    }
+
+    void set_backtrack(jit::Label* backtrack) { backtrack_ = backtrack; }
+    void set_stop_node(RegExpNode* node) { stop_node_ = node; }
+    void set_loop_label(jit::Label* label) { loop_label_ = label; }
+    void set_characters_preloaded(int count) { characters_preloaded_ = count; }
+    void set_bound_checked_up_to(int to) { bound_checked_up_to_ = to; }
+    void set_flush_budget(int to) { flush_budget_ = to; }
+    void set_quick_check_performed(QuickCheckDetails* d) {
+        quick_check_performed_ = *d;
+    }
+    void InvalidateCurrentCharacter();
+    void AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler);
+
+  private:
+    int FindAffectedRegisters(LifoAlloc *alloc, OutSet* affected_registers);
+    void PerformDeferredActions(LifoAlloc *alloc,
+                                RegExpMacroAssembler* macro,
+                                int max_register,
+                                OutSet& affected_registers,
+                                OutSet* registers_to_pop,
+                                OutSet* registers_to_clear);
+    void RestoreAffectedRegisters(RegExpMacroAssembler* macro,
+                                  int max_register,
+                                  OutSet& registers_to_pop,
+                                  OutSet& registers_to_clear);
+    int cp_offset_;
+    DeferredAction* actions_;
+    jit::Label* backtrack_;
+    RegExpNode* stop_node_;
+    jit::Label* loop_label_;
+    int characters_preloaded_;
+    int bound_checked_up_to_;
+    QuickCheckDetails quick_check_performed_;
+    int flush_budget_;
+    TriBool at_start_;
+};
+
+class NodeVisitor
+{
+  public:
+    virtual ~NodeVisitor() { }
+#define DECLARE_VISIT(Type)                                          \
+    virtual void Visit##Type(Type##Node* that) = 0;
+    FOR_EACH_NODE_TYPE(DECLARE_VISIT)
+#undef DECLARE_VISIT
+    virtual void VisitLoopChoice(LoopChoiceNode* that) { VisitChoice(that); }
+};
+
+// Assertion propagation moves information about assertions such as
+// \b to the affected nodes.  For instance, in /.\b./ information must
+// be propagated to the first '.' that whatever follows needs to know
+// if it matched a word or a non-word, and to the second '.' that it
+// has to check if it succeeds a word or non-word.  In this case the
+// result will be something like:
+//
+//   +-------+        +------------+
+//   |   .   |        |      .     |
+//   +-------+  --->  +------------+
+//   | word? |        | check word |
+//   +-------+        +------------+
+class Analysis : public NodeVisitor
+{
+  public:
+    Analysis(JSContext *cx, bool ignore_case, bool is_ascii)
+      : cx(cx),
+        ignore_case_(ignore_case),
+        is_ascii_(is_ascii),
+        error_message_(nullptr)
+    {}
+
+    void EnsureAnalyzed(RegExpNode* node);
+
+#define DECLARE_VISIT(Type)                     \
+    virtual void Visit##Type(Type##Node* that);
+    FOR_EACH_NODE_TYPE(DECLARE_VISIT)
+#undef DECLARE_VISIT
+    virtual void VisitLoopChoice(LoopChoiceNode* that);
+
+    bool has_failed() { return error_message_ != nullptr; }
+    const char* errorMessage() {
+        JS_ASSERT(error_message_ != nullptr);
+        return error_message_;
+    }
+    void fail(const char* error_message) {
+        error_message_ = error_message;
+    }
+
+  private:
+    JSContext *cx;
+    bool ignore_case_;