Merge regexp2000 back into bleeding_edge
authorchristian.plesner.hansen@gmail.com <christian.plesner.hansen@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 25 Nov 2008 11:07:48 +0000 (11:07 +0000)
committerchristian.plesner.hansen@gmail.com <christian.plesner.hansen@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 25 Nov 2008 11:07:48 +0000 (11:07 +0000)
Review URL: http://codereview.chromium.org/12427

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

53 files changed:
src/SConscript
src/assembler-ia32-inl.h
src/assembler-ia32.cc
src/assembler-ia32.h
src/assembler-irregexp-inl.h [new file with mode: 0644]
src/assembler-irregexp.cc [new file with mode: 0644]
src/assembler-irregexp.h [new file with mode: 0644]
src/assembler.h
src/ast.cc
src/ast.h
src/builtins.cc
src/bytecodes-irregexp.h [new file with mode: 0644]
src/checks.h
src/constants-arm.h
src/factory.cc
src/factory.h
src/flag-definitions.h
src/globals.h
src/heap.cc
src/heap.h
src/interpreter-irregexp.cc [new file with mode: 0644]
src/interpreter-irregexp.h [new file with mode: 0644]
src/jsregexp-inl.h [new file with mode: 0644]
src/jsregexp.cc
src/jsregexp.h
src/list-inl.h
src/list.h
src/objects-debug.cc
src/objects-inl.h
src/objects.cc
src/objects.h
src/parser.cc
src/parser.h
src/regexp-macro-assembler-ia32.cc [new file with mode: 0644]
src/regexp-macro-assembler-ia32.h [new file with mode: 0644]
src/regexp-macro-assembler-irregexp.cc [new file with mode: 0644]
src/regexp-macro-assembler-irregexp.h [new file with mode: 0644]
src/regexp-macro-assembler.cc [new file with mode: 0644]
src/regexp-macro-assembler.h [new file with mode: 0644]
src/runtime.cc
src/string-stream.cc
src/string-stream.h
src/stub-cache.cc
src/unicode.cc
src/unicode.h
src/utils.h
test/cctest/SConscript
test/cctest/test-regexp.cc [new file with mode: 0644]
test/mjsunit/non-ascii-replace.js
test/mjsunit/regexp.js
test/mjsunit/regress/regress-149.js [new file with mode: 0644]
test/mjsunit/unicode-test.js
test/mozilla/mozilla.status

index 8226a8d..f12f301 100644 (file)
@@ -35,15 +35,17 @@ Import('context')
 
 SOURCES = {
   'all': [
-    'accessors.cc', 'allocation.cc', 'api.cc', 'assembler.cc', 'ast.cc',
-    'bootstrapper.cc', 'builtins.cc', 'checks.cc', 'code-stubs.cc',
-    'codegen.cc', 'compilation-cache.cc', 'compiler.cc', 'contexts.cc',
-    'conversions.cc', 'counters.cc', 'dateparser.cc', 'debug.cc',
-    'disassembler.cc', 'execution.cc', 'factory.cc', 'flags.cc', 'frames.cc',
-    'global-handles.cc', 'handles.cc', 'hashmap.cc', 'heap.cc', 'ic.cc',
-    'jsregexp.cc', 'log.cc', 'mark-compact.cc', 'messages.cc', 'objects.cc',
-    'parser.cc', 'property.cc', 'rewriter.cc', 'runtime.cc', 'scanner.cc',
-    'scopeinfo.cc', 'scopes.cc', 'serialize.cc', 'snapshot-common.cc',
+    'accessors.cc', 'allocation.cc', 'api.cc', 'assembler.cc',
+    'assembler-irregexp.cc', 'ast.cc', 'bootstrapper.cc', 'builtins.cc',
+    'checks.cc', 'code-stubs.cc', 'codegen.cc', 'compilation-cache.cc',
+    'compiler.cc', 'contexts.cc', 'conversions.cc', 'counters.cc',
+    'dateparser.cc', 'debug.cc', 'disassembler.cc', 'execution.cc',
+    'factory.cc', 'flags.cc', 'frames.cc', 'global-handles.cc',
+    'handles.cc', 'hashmap.cc', 'heap.cc', 'ic.cc', 'interpreter-irregexp.cc',
+    'jsregexp.cc', 'log.cc', 'mark-compact.cc', 'messages.cc',
+    'objects.cc', 'parser.cc', 'property.cc', 'regexp-macro-assembler.cc',
+    'regexp-macro-assembler-irregexp.cc', 'rewriter.cc', 'runtime.cc', 'scanner.cc',
+    'scopeinfo.cc', 'scopes.cc', 'serialize.cc', 'snapshot-common.cc', 
     'spaces.cc', 'string-stream.cc', 'stub-cache.cc', 'token.cc', 'top.cc',
     'unicode.cc', 'usage-analyzer.cc', 'utils.cc', 'v8-counters.cc',
     'v8.cc', 'v8threads.cc', 'variables.cc', 'zone.cc'
@@ -53,7 +55,8 @@ SOURCES = {
       'macro-assembler-arm.cc', 'stub-cache-arm.cc'],
   'arch:ia32': ['assembler-ia32.cc', 'builtins-ia32.cc', 'codegen-ia32.cc',
       'cpu-ia32.cc', 'disasm-ia32.cc', 'frames-ia32.cc', 'ic-ia32.cc',
-      'macro-assembler-ia32.cc', 'stub-cache-ia32.cc'],
+      'macro-assembler-ia32.cc', 'regexp-macro-assembler-ia32.cc', 
+      'stub-cache-ia32.cc'],
   'simulator:arm': ['simulator-arm.cc'],
   'os:freebsd': ['platform-freebsd.cc'],
   'os:linux':   ['platform-linux.cc'],
index 9b3567a..534d57e 100644 (file)
@@ -205,6 +205,14 @@ void Assembler::emit(const Immediate& x) {
 }
 
 
+void Assembler::emit_w(const Immediate& x) {
+  ASSERT(x.rmode_ == RelocInfo::NONE);
+  uint16_t value = static_cast<uint16_t>(x.x_);
+  reinterpret_cast<uint16_t*>(pc_)[0] = value;
+  pc_ += sizeof(uint16_t);
+}
+
+
 Address Assembler::target_address_at(Address pc) {
   return pc + sizeof(int32_t) + *reinterpret_cast<int32_t*>(pc);
 }
index 264ef42..1555ecc 100644 (file)
@@ -122,7 +122,8 @@ void CpuFeatures::Probe() {
 #undef __
   CodeDesc desc;
   assm.GetCode(&desc);
-  Object* code = Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB));
+  Object* code =
+      Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB), NULL);
   if (!code->IsCode()) return;
   F0 f = FUNCTION_CAST<F0>(Code::cast(code)->entry());
   uint32_t res = f();
@@ -294,7 +295,6 @@ Assembler::Assembler(void* buffer, int buffer_size) {
     }
     buffer_size_ = buffer_size;
     own_buffer_ = true;
-
   } else {
     // use externally provided buffer instead
     ASSERT(buffer_size > 0);
@@ -420,6 +420,29 @@ void Assembler::push(const Operand& src) {
 }
 
 
+void Assembler::push(Label* label, RelocInfo::Mode reloc_mode) {
+  ASSERT_NOT_NULL(label);
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  // If reloc_mode == NONE, the label is stored as buffer relative.
+  ASSERT(reloc_mode == RelocInfo::NONE);
+  if (label->is_bound()) {
+    // Index of position in Code object:
+    int pos = label->pos() + Code::kHeaderSize;
+    if (pos >= 0 && pos < 256) {
+      EMIT(0x6a);
+      EMIT(pos);
+    } else {
+      EMIT(0x68);
+      emit(pos);
+    }
+  } else {
+    EMIT(0x68);
+    emit_disp(label, Displacement::CODE_RELATIVE);
+  }
+}
+
+
 void Assembler::pop(Register dst) {
   ASSERT(reloc_info_writer.last_pc() != NULL);
   if (FLAG_push_pop_elimination && (reloc_info_writer.last_pc() <= last_pc_)) {
@@ -546,6 +569,22 @@ void Assembler::pop(const Operand& dst) {
 }
 
 
+void Assembler::enter(const Immediate& size) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xC8);
+  emit_w(size);
+  EMIT(0);
+}
+
+
+void Assembler::leave() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xC9);
+}
+
+
 void Assembler::mov_b(Register dst, const Operand& src) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -830,6 +869,23 @@ void Assembler::cmp(const Operand& op, const Immediate& imm) {
 }
 
 
+void Assembler::rep_cmpsb() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xFC);  // CLD to ensure forward operation
+  EMIT(0xF3);  // REP
+  EMIT(0xA6);  // CMPSB
+}
+
+void Assembler::rep_cmpsw() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xFC);  // CLD to ensure forward operation
+  EMIT(0xF3);  // REP
+  EMIT(0xA7);  // CMPSW
+}
+
+
 void Assembler::dec_b(Register dst) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -1074,6 +1130,14 @@ void Assembler::shr(Register dst) {
 }
 
 
+void Assembler::shr_cl(Register dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD1);
+  EMIT(0xE8 | dst.code());
+}
+
+
 void Assembler::sub(const Operand& dst, const Immediate& x) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -1171,6 +1235,15 @@ void Assembler::xor_(const Operand& dst, const Immediate& x) {
 }
 
 
+void Assembler::bt(const Operand& dst, Register src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x0F);
+  EMIT(0xA3);
+  emit_operand(src, dst);
+}
+
+
 void Assembler::bts(const Operand& dst, Register src) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -1224,13 +1297,6 @@ void Assembler::ret(int imm16) {
 }
 
 
-void Assembler::leave() {
-  EnsureSpace ensure_space(this);
-  last_pc_ = pc_;
-  EMIT(0xC9);
-}
-
-
 // Labels refer to positions in the (to be) generated code.
 // There are bound, linked, and unused labels.
 //
@@ -1270,12 +1336,16 @@ void Assembler::bind_to(Label* L, int pos) {
   while (L->is_linked()) {
     Displacement disp = disp_at(L);
     int fixup_pos = L->pos();
-    if (disp.type() == Displacement::UNCONDITIONAL_JUMP) {
-      ASSERT(byte_at(fixup_pos - 1) == 0xE9);  // jmp expected
+    if (disp.type() == Displacement::CODE_RELATIVE) {
+      long_at_put(fixup_pos, pos + Code::kHeaderSize);
+    } else {
+      if (disp.type() == Displacement::UNCONDITIONAL_JUMP) {
+        ASSERT(byte_at(fixup_pos - 1) == 0xE9);  // jmp expected
+      }
+      // relative address, relative to point after address
+      int imm32 = pos - (fixup_pos + sizeof(int32_t));
+      long_at_put(fixup_pos, imm32);
     }
-    // relative address, relative to point after address
-    int imm32 = pos - (fixup_pos + sizeof(int32_t));
-    long_at_put(fixup_pos, imm32);
     disp.next(L);
   }
   L->bind_to(pos);
index 9647446..3efd2f2 100644 (file)
@@ -118,8 +118,8 @@ enum Condition {
   not_equal     =  5,
   below_equal   =  6,
   above         =  7,
-  sign          =  8,
-  not_sign      =  9,
+  negative      =  8,
+  positive      =  9,
   parity_even   = 10,
   parity_odd    = 11,
   less          = 12,
@@ -128,10 +128,12 @@ enum Condition {
   greater       = 15,
 
   // aliases
+  carry         = below,
+  not_carry     = above_equal,
   zero          = equal,
   not_zero      = not_equal,
-  negative      = sign,
-  positive      = not_sign
+  sign          = negative,
+  not_sign      = positive
 };
 
 
@@ -283,13 +285,14 @@ class Operand BASE_EMBEDDED {
 //
 // Displacement _data field layout
 //
-// |31.....1| ......0|
+// |31.....2|1......0|
 // [  next  |  type  |
 
 class Displacement BASE_EMBEDDED {
  public:
   enum Type {
     UNCONDITIONAL_JUMP,
+    CODE_RELATIVE,
     OTHER
   };
 
@@ -313,8 +316,8 @@ class Displacement BASE_EMBEDDED {
  private:
   int data_;
 
-  class TypeField: public BitField<Type, 0, 1> {};
-  class NextField: public BitField<int,  1, 32-1> {};
+  class TypeField: public BitField<Type, 0, 2> {};
+  class NextField: public BitField<int,  2, 32-2> {};
 
   void init(Label* L, Type type);
 };
@@ -440,10 +443,14 @@ class Assembler : public Malloced {
   void push(const Immediate& x);
   void push(Register src);
   void push(const Operand& src);
+  void push(Label* label, RelocInfo::Mode relocation_mode);
 
   void pop(Register dst);
   void pop(const Operand& dst);
 
+  void enter(const Immediate& size);
+  void leave();
+
   // Moves
   void mov_b(Register dst, const Operand& src);
   void mov_b(const Operand& dst, int8_t imm8);
@@ -491,6 +498,9 @@ class Assembler : public Malloced {
   void cmp(Register reg, const Operand& op);
   void cmp(const Operand& op, const Immediate& imm);
 
+  void rep_cmpsb();
+  void rep_cmpsw();
+
   void dec_b(Register dst);
 
   void dec(Register dst);
@@ -535,6 +545,7 @@ class Assembler : public Malloced {
 
   void shr(Register dst, uint8_t imm8);
   void shr(Register dst);
+  void shr_cl(Register dst);
 
   void sub(const Operand& dst, const Immediate& x);
   void sub(Register dst, const Operand& src);
@@ -550,6 +561,7 @@ class Assembler : public Malloced {
   void xor_(const Operand& dst, const Immediate& x);
 
   // Bit operations.
+  void bt(const Operand& dst, Register src);
   void bts(const Operand& dst, Register src);
 
   // Miscellaneous
@@ -558,7 +570,6 @@ class Assembler : public Malloced {
   void nop();
   void rdtsc();
   void ret(int imm16);
-  void leave();
 
   // Label operations & relative jumps (PPUM Appendix D)
   //
@@ -748,6 +759,7 @@ class Assembler : public Malloced {
   inline void emit(Handle<Object> handle);
   inline void emit(uint32_t x, RelocInfo::Mode rmode);
   inline void emit(const Immediate& x);
+  inline void emit_w(const Immediate& x);
 
   // instruction generation
   void emit_arith_b(int op1, int op2, Register dst, int imm8);
diff --git a/src/assembler-irregexp-inl.h b/src/assembler-irregexp-inl.h
new file mode 100644 (file)
index 0000000..d4faeea
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright 2008 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.
+
+// A light-weight assembler for the Regexp2000 byte code.
+
+
+#include "v8.h"
+#include "ast.h"
+#include "bytecodes-irregexp.h"
+#include "assembler-irregexp.h"
+
+
+namespace v8 { namespace internal {
+
+
+void IrregexpAssembler::Emit(uint32_t byte) {
+  ASSERT(pc_ <= buffer_.length());
+  if (pc_ == buffer_.length()) {
+    Expand();
+  }
+  buffer_[pc_++] = byte;
+}
+
+
+void IrregexpAssembler::Emit16(uint32_t word) {
+  ASSERT(pc_ <= buffer_.length());
+  if (pc_ + 1 >= buffer_.length()) {
+    Expand();
+  }
+  Store16(buffer_.start() + pc_, word);
+  pc_ += 2;
+}
+
+
+void IrregexpAssembler::Emit32(uint32_t word) {
+  ASSERT(pc_ <= buffer_.length());
+  if (pc_ + 3 >= buffer_.length()) {
+    Expand();
+  }
+  Store32(buffer_.start() + pc_, word);
+  pc_ += 4;
+}
+
+
+void IrregexpAssembler::EmitOrLink(Label* l) {
+    if (l->is_bound()) {
+      Emit32(l->pos());
+    } else {
+      int pos = 0;
+      if (l->is_linked()) {
+        pos = l->pos();
+      }
+      l->link_to(pc_);
+      Emit32(pos);
+    }
+  }
+
+} }  // namespace v8::internal
diff --git a/src/assembler-irregexp.cc b/src/assembler-irregexp.cc
new file mode 100644 (file)
index 0000000..bc3d0ae
--- /dev/null
@@ -0,0 +1,339 @@
+// Copyright 2008 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.
+
+// A light-weight assembler for the Irregexp byte code.
+
+
+#include "v8.h"
+#include "ast.h"
+#include "bytecodes-irregexp.h"
+#include "assembler-irregexp.h"
+
+#include "assembler-irregexp-inl.h"
+
+
+namespace v8 { namespace internal {
+
+
+IrregexpAssembler::IrregexpAssembler(Vector<byte> buffer)
+  : buffer_(buffer),
+    pc_(0),
+    own_buffer_(false) {
+}
+
+
+IrregexpAssembler::~IrregexpAssembler() {
+  if (own_buffer_) {
+    buffer_.Dispose();
+  }
+}
+
+
+void IrregexpAssembler::PushCurrentPosition(int cp_offset) {
+  ASSERT(cp_offset >= 0);
+  Emit(BC_PUSH_CP);
+  Emit32(cp_offset);
+}
+
+
+void IrregexpAssembler::PushBacktrack(Label* l) {
+  Emit(BC_PUSH_BT);
+  EmitOrLink(l);
+}
+
+
+void IrregexpAssembler::PushRegister(int index) {
+  ASSERT(index >= 0);
+  Emit(BC_PUSH_REGISTER);
+  Emit(index);
+}
+
+
+void IrregexpAssembler::WriteCurrentPositionToRegister(int index,
+                                                       int cp_offset) {
+  ASSERT(cp_offset >= 0);
+  ASSERT(index >= 0);
+  Emit(BC_SET_REGISTER_TO_CP);
+  Emit(index);
+  Emit32(cp_offset);
+}
+
+
+void IrregexpAssembler::ReadCurrentPositionFromRegister(int index) {
+  ASSERT(index >= 0);
+  Emit(BC_SET_CP_TO_REGISTER);
+  Emit(index);
+}
+
+
+void IrregexpAssembler::WriteStackPointerToRegister(int index) {
+  ASSERT(index >= 0);
+  Emit(BC_SET_REGISTER_TO_SP);
+  Emit(index);
+}
+
+
+void IrregexpAssembler::ReadStackPointerFromRegister(int index) {
+  ASSERT(index >= 0);
+  Emit(BC_SET_SP_TO_REGISTER);
+  Emit(index);
+}
+
+
+void IrregexpAssembler::SetRegister(int index, int value) {
+  ASSERT(index >= 0);
+  Emit(BC_SET_REGISTER);
+  Emit(index);
+  Emit32(value);
+}
+
+
+void IrregexpAssembler::AdvanceRegister(int index, int by) {
+  ASSERT(index >= 0);
+  Emit(BC_ADVANCE_REGISTER);
+  Emit(index);
+  Emit32(by);
+}
+
+
+void IrregexpAssembler::PopCurrentPosition() {
+  Emit(BC_POP_CP);
+}
+
+
+void IrregexpAssembler::PopBacktrack() {
+  Emit(BC_POP_BT);
+}
+
+
+void IrregexpAssembler::PopRegister(int index) {
+  Emit(BC_POP_REGISTER);
+  Emit(index);
+}
+
+
+void IrregexpAssembler::Fail() {
+  Emit(BC_FAIL);
+}
+
+
+void IrregexpAssembler::Break() {
+  Emit(BC_BREAK);
+}
+
+
+void IrregexpAssembler::Succeed() {
+  Emit(BC_SUCCEED);
+}
+
+
+void IrregexpAssembler::Bind(Label* l) {
+  ASSERT(!l->is_bound());
+  if (l->is_linked()) {
+    int pos = l->pos();
+    while (pos != 0) {
+      int fixup = pos;
+      pos = Load32(buffer_.start() + fixup);
+      Store32(buffer_.start() + fixup, pc_);
+    }
+  }
+  l->bind_to(pc_);
+}
+
+
+void IrregexpAssembler::AdvanceCP(int cp_offset) {
+  Emit(BC_ADVANCE_CP);
+  Emit32(cp_offset);
+}
+
+
+void IrregexpAssembler::GoTo(Label* l) {
+  Emit(BC_GOTO);
+  EmitOrLink(l);
+}
+
+
+void IrregexpAssembler::LoadCurrentChar(int cp_offset, Label* on_end) {
+  Emit(BC_LOAD_CURRENT_CHAR);
+  Emit32(cp_offset);
+  EmitOrLink(on_end);
+}
+
+
+void IrregexpAssembler::CheckCharacter(uc16 c, Label* on_match) {
+  Emit(BC_CHECK_CHAR);
+  Emit16(c);
+  EmitOrLink(on_match);
+}
+
+
+void IrregexpAssembler::CheckNotCharacter(uc16 c, Label* on_mismatch) {
+  Emit(BC_CHECK_NOT_CHAR);
+  Emit16(c);
+  EmitOrLink(on_mismatch);
+}
+
+void IrregexpAssembler::OrThenCheckNotCharacter(uc16 c,
+                                                uc16 mask,
+                                                Label* on_mismatch) {
+  Emit(BC_OR_CHECK_NOT_CHAR);
+  Emit16(c);
+  Emit16(mask);
+  EmitOrLink(on_mismatch);
+}
+
+
+void IrregexpAssembler::MinusOrThenCheckNotCharacter(uc16 c,
+                                                     uc16 mask,
+                                                     Label* on_mismatch) {
+  Emit(BC_MINUS_OR_CHECK_NOT_CHAR);
+  Emit16(c);
+  Emit16(mask);
+  EmitOrLink(on_mismatch);
+}
+
+
+void IrregexpAssembler::CheckCharacterLT(uc16 limit, Label* on_less) {
+  Emit(BC_CHECK_LT);
+  Emit16(limit);
+  EmitOrLink(on_less);
+}
+
+
+void IrregexpAssembler::CheckCharacterGT(uc16 limit, Label* on_greater) {
+  Emit(BC_CHECK_GT);
+  Emit16(limit);
+  EmitOrLink(on_greater);
+}
+
+
+void IrregexpAssembler::CheckNotBackReference(int capture_index,
+                                          Label* on_mismatch) {
+  Emit(BC_CHECK_NOT_BACK_REF);
+  Emit(capture_index);
+  EmitOrLink(on_mismatch);
+}
+
+
+void IrregexpAssembler::CheckRegister(int byte_code,
+                                      int reg_index,
+                                      uint16_t vs,
+                                      Label* on_true) {
+  Emit(byte_code);
+  Emit(reg_index);
+  Emit16(vs);
+  EmitOrLink(on_true);
+}
+
+
+void IrregexpAssembler::CheckRegisterLT(int reg_index,
+                                        uint16_t vs,
+                                        Label* on_less_than) {
+  CheckRegister(BC_CHECK_REGISTER_LT, reg_index, vs, on_less_than);
+}
+
+
+void IrregexpAssembler::CheckRegisterGE(int reg_index,
+                                        uint16_t vs,
+                                        Label* on_greater_than_equal) {
+  CheckRegister(BC_CHECK_REGISTER_GE, reg_index, vs, on_greater_than_equal);
+}
+
+
+void IrregexpAssembler::LookupMap1(uc16 start, Label* bit_map, Label* on_zero) {
+  Emit(BC_LOOKUP_MAP1);
+  Emit16(start);
+  EmitOrLink(bit_map);
+  EmitOrLink(on_zero);
+}
+
+
+void IrregexpAssembler::LookupMap2(uc16 start,
+                                   Label* half_nibble_map,
+                                   const Vector<Label*>& table) {
+  Emit(BC_LOOKUP_MAP2);
+  Emit16(start);
+  EmitOrLink(half_nibble_map);
+  ASSERT(table.length() > 0);
+  ASSERT(table.length() <= 4);
+  for (int i = 0; i < table.length(); i++) {
+    EmitOrLink(table[i]);
+  }
+}
+
+
+void IrregexpAssembler::LookupMap8(uc16 start,
+                                   Label* byte_map,
+                                   const Vector<Label*>& table) {
+  Emit(BC_LOOKUP_MAP8);
+  Emit16(start);
+  EmitOrLink(byte_map);
+  ASSERT(table.length() > 0);
+  ASSERT(table.length() <= 256);
+  for (int i = 0; i < table.length(); i++) {
+    EmitOrLink(table[i]);
+  }
+}
+
+
+void IrregexpAssembler::LookupHighMap8(byte start,
+                                       Label* byte_map,
+                                       const Vector<Label*>& table) {
+  Emit(BC_LOOKUP_HI_MAP8);
+  Emit(start);
+  EmitOrLink(byte_map);
+  ASSERT(table.length() > 0);
+  ASSERT(table.length() <= 256);
+  for (int i = 0; i < table.length(); i++) {
+    EmitOrLink(table[i]);
+  }
+}
+
+
+int IrregexpAssembler::length() {
+  return pc_;
+}
+
+
+void IrregexpAssembler::Copy(Address a) {
+  memcpy(a, buffer_.start(), length());
+}
+
+
+void IrregexpAssembler::Expand() {
+  bool old_buffer_was_our_own = own_buffer_;
+  Vector<byte> old_buffer = buffer_;
+  buffer_ = Vector<byte>::New(old_buffer.length() * 2);
+  own_buffer_ = true;
+  memcpy(buffer_.start(), old_buffer.start(), old_buffer.length());
+  if (old_buffer_was_our_own) {
+    old_buffer.Dispose();
+  }
+}
+
+
+} }  // namespace v8::internal
diff --git a/src/assembler-irregexp.h b/src/assembler-irregexp.h
new file mode 100644 (file)
index 0000000..9852521
--- /dev/null
@@ -0,0 +1,137 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+// A light-weight assembler for the Irregexp byte code.
+
+#ifndef V8_ASSEMBLER_IRREGEXP_H_
+#define V8_ASSEMBLER_IRREGEXP_H_
+
+namespace v8 { namespace internal {
+
+
+class IrregexpAssembler {
+ public:
+  // Create an assembler. Instructions and relocation information are emitted
+  // into a buffer, with the instructions starting from the beginning and the
+  // relocation information starting from the end of the buffer. See CodeDesc
+  // for a detailed comment on the layout (globals.h).
+  //
+  // If the provided buffer is NULL, the assembler allocates and grows its own
+  // buffer, and buffer_size determines the initial buffer size. The buffer is
+  // owned by the assembler and deallocated upon destruction of the assembler.
+  //
+  // If the provided buffer is not NULL, the assembler uses the provided buffer
+  // for code generation and assumes its size to be buffer_size. If the buffer
+  // is too small, a fatal error occurs. No deallocation of the buffer is done
+  // upon destruction of the assembler.
+  explicit IrregexpAssembler(Vector<byte>);
+  ~IrregexpAssembler();
+
+  // CP = current position in source.
+  // BT = backtrack label.
+
+  // Stack.
+  void PushCurrentPosition(int cp_offset = 0);
+  void PushBacktrack(Label* l);
+  void PushRegister(int index);
+  void WriteCurrentPositionToRegister(int index, int cp_offset = 0);
+  void ReadCurrentPositionFromRegister(int index);
+  void WriteStackPointerToRegister(int index);
+  void ReadStackPointerFromRegister(int index);
+  void SetRegister(int index, int value);
+  void AdvanceRegister(int index, int by);
+
+  void PopCurrentPosition();
+  void PopBacktrack();
+  void PopRegister(int index);
+
+  void Fail();
+  void Succeed();
+
+  void Break();  // This instruction will cause a fatal VM error if hit.
+
+  void Bind(Label* l);  // Binds an unbound label L to the current code posn.
+
+  void AdvanceCP(int by);
+
+  void GoTo(Label* l);
+
+  // Loads current char into a machine register.  Jumps to the label if we
+  // reached the end of the subject string.  Fall through otherwise.
+  void LoadCurrentChar(int cp_offset, Label* on_end);
+
+  // Checks current char register against a singleton.
+  void CheckCharacter(uc16 c, Label* on_match);
+  void CheckNotCharacter(uc16 c, Label* on_mismatch);
+  void OrThenCheckNotCharacter(uc16 c, uc16 mask, Label* on_mismatch);
+  void MinusOrThenCheckNotCharacter(uc16 c, uc16 mask, Label* on_mismatch);
+
+  // Used to check current char register against a range.
+  void CheckCharacterLT(uc16 limit, Label* on_less);
+  void CheckCharacterGT(uc16 limit, Label* on_greater);
+
+  // Checks current position for a match against a
+  // previous capture.  Advances current position by the length of the capture
+  // iff it matches.  The capture is stored in a given register and the
+  // the register after.  If a register contains -1 then the other register
+  // must always contain -1 and the on_mismatch label will never be called.
+  void CheckNotBackReference(int capture_index, Label* on_mismatch);
+
+  // Checks a register for strictly-less-than or greater-than-or-equal.
+  void CheckRegisterLT(int reg_index, uint16_t vs, Label* on_less_than);
+  void CheckRegisterGE(int reg_index, uint16_t vs, Label* on_greater_equal);
+
+  // Subtracts a 16 bit value from the current character, uses the result to
+  // look up in a bit array, uses the result of that decide whether to fall
+  // though (on 1) or jump to the on_zero label (on 0).
+  void LookupMap1(uc16 start, Label* bit_map, Label* on_zero);
+
+  // Subtracts a 16 bit value from the current character, uses the result to
+  // look up in a 2-bit array, uses the result of that to look up in a label
+  // table and jumps to the label.
+  void LookupMap2(uc16 start,
+                  Label* half_nibble_map,
+                  const Vector<Label*>& table);
+
+  // Subtracts a 16 bit value from the current character, uses the result to
+  // look up in a byte array, uses the result of that to look up in a label
+  // array and jumps to the label.
+  void LookupMap8(uc16 start, Label* byte_map, const Vector<Label*>& table);
+
+  // Takes the high byte of the current character, uses the result to
+  // look up in a byte array, uses the result of that to look up in a label
+  // array and jumps to the label.
+  void LookupHighMap8(byte start, Label* byte_map, const Vector<Label*>& table);
+
+  // Code and bitmap emission.
+  inline void Emit32(uint32_t x);
+  inline void Emit16(uint32_t x);
+  inline void Emit(uint32_t x);
+
+  // Bytecode buffer.
+  int length();
+  void Copy(Address a);
+
+  inline void EmitOrLink(Label* l);
+ private:
+  // Don't use this.
+  IrregexpAssembler() { UNREACHABLE(); }
+  // The buffer into which code and relocation info are generated.
+  Vector<byte> buffer_;
+
+  inline void CheckRegister(int byte_code,
+                            int reg_index,
+                            uint16_t vs,
+                            Label* on_true);
+  // Code generation.
+  int pc_;  // The program counter; moves forward.
+
+  // True if the assembler owns the buffer, false if buffer is external.
+  bool own_buffer_;
+
+  void Expand();
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_ASSEMBLER_IRREGEXP_H_
index 81c8056..b613d9b 100644 (file)
@@ -50,7 +50,8 @@ namespace v8 { namespace internal {
 
 class Label : public ZoneObject {  // LabelShadows are dynamically allocated.
  public:
-  INLINE(Label())                 { Unuse(); }
+  INLINE(Label())
+  { Unuse(); }
   INLINE(~Label())                { ASSERT(!is_linked()); }
 
   INLINE(void Unuse())            { pos_ = 0; }
@@ -82,8 +83,10 @@ class Label : public ZoneObject {  // LabelShadows are dynamically allocated.
   }
 
   friend class Assembler;
+  friend class RegexpAssembler;
   friend class Displacement;
   friend class LabelShadow;
+  friend class IrregexpAssembler;
 };
 
 
index 2f21d92..ce4dfb8 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "ast.h"
 #include "scopes.h"
+#include "string-stream.h"
 
 namespace v8 { namespace internal {
 
@@ -179,4 +180,204 @@ void Visitor::VisitExpressions(ZoneList<Expression*>* expressions) {
 }
 
 
+// ----------------------------------------------------------------------------
+// Regular expressions
+
+#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 NULL;                                                     \
+  }                                                                  \
+  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
+
+RegExpEmpty RegExpEmpty::kInstance;
+
+
+// Convert regular expression trees to a simple sexp representation.
+// This representation should be different from the input grammar
+// in as many cases as possible, to make it more difficult for incorrect
+// parses to look as correct ones which is likely if the input and
+// output formats are alike.
+class RegExpUnparser: public RegExpVisitor {
+ public:
+  RegExpUnparser();
+  void VisitCharacterRange(CharacterRange that);
+  SmartPointer<const char> ToString() { return stream_.ToCString(); }
+#define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, void* data);
+  FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
+#undef MAKE_CASE
+ private:
+  StringStream* stream() { return &stream_; }
+  HeapStringAllocator alloc_;
+  StringStream stream_;
+};
+
+
+RegExpUnparser::RegExpUnparser() : stream_(&alloc_) {
+}
+
+
+void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) {
+  stream()->Add("(|");
+  for (int i = 0; i <  that->alternatives()->length(); i++) {
+    stream()->Add(" ");
+    that->alternatives()->at(i)->Accept(this, data);
+  }
+  stream()->Add(")");
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) {
+  stream()->Add("(:");
+  for (int i = 0; i <  that->nodes()->length(); i++) {
+    stream()->Add(" ");
+    that->nodes()->at(i)->Accept(this, data);
+  }
+  stream()->Add(")");
+  return NULL;
+}
+
+
+void RegExpUnparser::VisitCharacterRange(CharacterRange that) {
+  stream()->Add("%k", that.from());
+  if (!that.IsSingleton()) {
+    stream()->Add("-%k", that.to());
+  }
+}
+
+
+
+void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that,
+                                          void* data) {
+  if (that->is_negated())
+    stream()->Add("^");
+  stream()->Add("[");
+  for (int i = 0; i < that->ranges()->length(); i++) {
+    if (i > 0) stream()->Add(" ");
+    VisitCharacterRange(that->ranges()->at(i));
+  }
+  stream()->Add("]");
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) {
+  switch (that->type()) {
+    case RegExpAssertion::START_OF_INPUT:
+      stream()->Add("@^i");
+      break;
+    case RegExpAssertion::END_OF_INPUT:
+      stream()->Add("@$i");
+      break;
+    case RegExpAssertion::START_OF_LINE:
+      stream()->Add("@^l");
+      break;
+    case RegExpAssertion::END_OF_LINE:
+      stream()->Add("@$l");
+       break;
+    case RegExpAssertion::BOUNDARY:
+      stream()->Add("@b");
+      break;
+    case RegExpAssertion::NON_BOUNDARY:
+      stream()->Add("@B");
+      break;
+  }
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) {
+  stream()->Add("'");
+  Vector<const uc16> chardata = that->data();
+  for (int i = 0; i < chardata.length(); i++) {
+    stream()->Add("%k", chardata[i]);
+  }
+  stream()->Add("'");
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitText(RegExpText* that, void* data) {
+  if (that->elements()->length() == 1) {
+    that->elements()->at(0).data.u_atom->Accept(this, data);
+  } else {
+    stream()->Add("(!");
+    for (int i = 0; i < that->elements()->length(); i++) {
+      stream()->Add(" ");
+      that->elements()->at(i).data.u_atom->Accept(this, data);
+    }
+    stream()->Add(")");
+  }
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) {
+  stream()->Add("(# %i ", that->min());
+  if (that->max() == RegExpQuantifier::kInfinity) {
+    stream()->Add("- ");
+  } else {
+    stream()->Add("%i ", that->max());
+  }
+  stream()->Add(that->is_greedy() ? "g " : "n ");
+  that->body()->Accept(this, data);
+  stream()->Add(")");
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) {
+  stream()->Add("(^ ");
+  that->body()->Accept(this, data);
+  stream()->Add(")");
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) {
+  stream()->Add("(-> ");
+  stream()->Add(that->is_positive() ? "+ " : "- ");
+  that->body()->Accept(this, data);
+  stream()->Add(")");
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitBackReference(RegExpBackReference* that,
+                                         void* data) {
+  stream()->Add("(<- %i)", that->index());
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) {
+  stream()->Put('%');
+  return NULL;
+}
+
+
+SmartPointer<const char> RegExpTree::ToString() {
+  RegExpUnparser unparser;
+  Accept(&unparser, NULL);
+  return unparser.ToString();
+}
+
+
 } }  // namespace v8::internal
index b383f76..f3a03eb 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -34,6 +34,7 @@
 #include "token.h"
 #include "variables.h"
 #include "macro-assembler.h"
+#include "jsregexp.h"
 
 namespace v8 { namespace internal {
 
@@ -1192,6 +1193,268 @@ class ThisFunction: public Expression {
 
 
 // ----------------------------------------------------------------------------
+// Regular expressions
+
+
+class RegExpTree: public ZoneObject {
+ public:
+  virtual ~RegExpTree() { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data) = 0;
+  virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                             RegExpNode* on_success,
+                             RegExpNode* on_failure) = 0;
+  virtual bool IsTextElement() { return false; }
+  virtual void AppendToText(RegExpText* text);
+  SmartPointer<const char> ToString();
+#define MAKE_ASTYPE(Name)                                                  \
+  virtual RegExp##Name* As##Name();                                        \
+  virtual bool Is##Name();
+  FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ASTYPE)
+#undef MAKE_ASTYPE
+};
+
+
+class RegExpDisjunction: public RegExpTree {
+ public:
+  explicit RegExpDisjunction(ZoneList<RegExpTree*>* alternatives)
+    : alternatives_(alternatives) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                             RegExpNode* on_success,
+                             RegExpNode* on_failure);
+  virtual RegExpDisjunction* AsDisjunction();
+  virtual bool IsDisjunction();
+  ZoneList<RegExpTree*>* alternatives() { return alternatives_; }
+ private:
+  ZoneList<RegExpTree*>* alternatives_;
+};
+
+
+class RegExpAlternative: public RegExpTree {
+ public:
+  explicit RegExpAlternative(ZoneList<RegExpTree*>* nodes) : nodes_(nodes) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                             RegExpNode* on_success,
+                             RegExpNode* on_failure);
+  virtual RegExpAlternative* AsAlternative();
+  virtual bool IsAlternative();
+  ZoneList<RegExpTree*>* nodes() { return nodes_; }
+ private:
+  ZoneList<RegExpTree*>* nodes_;
+};
+
+
+class RegExpText: public RegExpTree {
+ public:
+  RegExpText() : elements_(2) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                             RegExpNode* on_success,
+                             RegExpNode* on_failure);
+  virtual RegExpText* AsText();
+  virtual bool IsText();
+  virtual bool IsTextElement() { return true; }
+  virtual void AppendToText(RegExpText* text);
+  void AddElement(TextElement elm) { elements_.Add(elm); }
+  ZoneList<TextElement>* elements() { return &elements_; }
+ private:
+  ZoneList<TextElement> elements_;
+};
+
+
+class RegExpAssertion: public RegExpTree {
+ public:
+  enum Type {
+    START_OF_LINE, START_OF_INPUT, END_OF_LINE, END_OF_INPUT,
+    BOUNDARY, NON_BOUNDARY
+  };
+  explicit RegExpAssertion(Type type) : type_(type) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                             RegExpNode* on_success,
+                             RegExpNode* on_failure);
+  virtual RegExpAssertion* AsAssertion();
+  virtual bool IsAssertion();
+  Type type() { return type_; }
+ private:
+  Type type_;
+};
+
+
+class RegExpCharacterClass: public RegExpTree {
+ public:
+  RegExpCharacterClass(ZoneList<CharacterRange>* ranges, bool is_negated)
+    : ranges_(ranges),
+      is_negated_(is_negated) { }
+  explicit RegExpCharacterClass(uc16 type)
+    : ranges_(new ZoneList<CharacterRange>(2)),
+      is_negated_(false) {
+    CharacterRange::AddClassEscape(type, ranges_);
+  }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                             RegExpNode* on_success,
+                             RegExpNode* on_failure);
+  virtual RegExpCharacterClass* AsCharacterClass();
+  virtual bool IsCharacterClass();
+  virtual bool IsTextElement() { return true; }
+  virtual void AppendToText(RegExpText* text);
+  ZoneList<CharacterRange>* ranges() { return ranges_; }
+  bool is_negated() { return is_negated_; }
+ private:
+  ZoneList<CharacterRange>* ranges_;
+  bool is_negated_;
+};
+
+
+class RegExpAtom: public RegExpTree {
+ public:
+  explicit RegExpAtom(Vector<const uc16> data) : data_(data) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                             RegExpNode* on_success,
+                             RegExpNode* on_failure);
+  virtual RegExpAtom* AsAtom();
+  virtual bool IsAtom();
+  virtual bool IsTextElement() { return true; }
+  virtual void AppendToText(RegExpText* text);
+  Vector<const uc16> data() { return data_; }
+ private:
+  Vector<const uc16> data_;
+};
+
+
+class RegExpQuantifier: public RegExpTree {
+ public:
+  RegExpQuantifier(int min, int max, bool is_greedy, RegExpTree* body)
+    : min_(min),
+      max_(max),
+      is_greedy_(is_greedy),
+      body_(body) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                             RegExpNode* on_success,
+                             RegExpNode* on_failure);
+  static RegExpNode* ToNode(int min,
+                            int max,
+                            bool is_greedy,
+                            RegExpTree* body,
+                            RegExpCompiler* compiler,
+                            RegExpNode* on_success,
+                            RegExpNode* on_failure);
+  virtual RegExpQuantifier* AsQuantifier();
+  virtual bool IsQuantifier();
+  int min() { return min_; }
+  int max() { return max_; }
+  bool is_greedy() { return is_greedy_; }
+  RegExpTree* body() { return body_; }
+  // We just use a very large integer value as infinity because 2^30
+  // is infinite in practice.
+  static const int kInfinity = (1 << 30);
+ private:
+  int min_;
+  int max_;
+  bool is_greedy_;
+  RegExpTree* body_;
+};
+
+
+enum CaptureAvailability {
+    CAPTURE_AVAILABLE, CAPTURE_UNREACHABLE, CAPTURE_PERMANENTLY_UNREACHABLE };
+
+class RegExpCapture: public RegExpTree {
+ public:
+  explicit RegExpCapture(RegExpTree* body, int index)
+    : body_(body), index_(index), available_(CAPTURE_AVAILABLE) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                             RegExpNode* on_success,
+                             RegExpNode* on_failure);
+  static RegExpNode* ToNode(RegExpTree* body,
+                            int index,
+                            RegExpCompiler* compiler,
+                            RegExpNode* on_success,
+                            RegExpNode* on_failure);
+  virtual RegExpCapture* AsCapture();
+  virtual bool IsCapture();
+  RegExpTree* body() { return body_; }
+  int index() { return index_; }
+  inline CaptureAvailability available() { return available_; }
+  inline void set_available(CaptureAvailability availability) {
+    available_ = availability;
+  }
+  static int StartRegister(int index) { return index * 2; }
+  static int EndRegister(int index) { return index * 2 + 1; }
+ private:
+  RegExpTree* body_;
+  int index_;
+  CaptureAvailability available_;
+};
+
+
+class RegExpLookahead: public RegExpTree {
+ public:
+  RegExpLookahead(RegExpTree* body, bool is_positive)
+    : body_(body),
+      is_positive_(is_positive) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpNode* ToNode(RegExpCompiler* compiler,
+                             RegExpNode* on_success,
+                             RegExpNode* on_failure);
+  virtual RegExpLookahead* AsLookahead();
+  virtual bool IsLookahead();
+  RegExpTree* body() { return body_; }
+  bool is_positive() { return is_positive_; }
+ private:
+  RegExpTree* body_;
+  bool is_positive_;
+};
+
+
+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,
+                             RegExpNode* on_failure);
+  virtual RegExpBackReference* AsBackReference();
+  virtual bool IsBackReference();
+  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,
+                             RegExpNode* on_failure);
+  virtual RegExpEmpty* AsEmpty();
+  virtual bool IsEmpty();
+  static RegExpEmpty* GetInstance() { return &kInstance; }
+ private:
+  static RegExpEmpty kInstance;
+};
+
+
+class RegExpVisitor BASE_EMBEDDED {
+ 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
+};
+
+
+// ----------------------------------------------------------------------------
 // Basic visitor
 // - leaf node visitors are abstract.
 
index fdff2d2..c44b2e2 100644 (file)
@@ -647,7 +647,7 @@ void Builtins::Setup(bool create_heap_objects) {
         // During startup it's OK to always allocate and defer GC to later.
         // This simplifies things because we don't need to retry.
         AlwaysAllocateScope __scope__;
-        code = Heap::CreateCode(desc, NULL, flags);
+        code = Heap::CreateCode(desc, NULL, flags, NULL);
         if (code->IsFailure()) {
           v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
         }
diff --git a/src/bytecodes-irregexp.h b/src/bytecodes-irregexp.h
new file mode 100644 (file)
index 0000000..9469c04
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright 2008 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 v8 { namespace internal {
+
+#define BYTECODE_ITERATOR(V)    \
+V(BREAK,              0, 1) /* break                                        */ \
+V(PUSH_CP,            1, 5) /* push_cp offset32                             */ \
+V(PUSH_BT,            2, 5) /* push_bt addr32                               */ \
+V(PUSH_REGISTER,      3, 2) /* push_register register_index                 */ \
+V(SET_REGISTER_TO_CP, 4, 6) /* set_register_to_cp register_index offset32   */ \
+V(SET_CP_TO_REGISTER, 5, 2) /* set_cp_to_registger register_index           */ \
+V(SET_REGISTER_TO_SP, 6, 2) /* set_register_to_sp register_index            */ \
+V(SET_SP_TO_REGISTER, 7, 2) /* set_sp_to_registger register_index           */ \
+V(SET_REGISTER,       8, 6) /* set_register register_index value32          */ \
+V(ADVANCE_REGISTER,   9, 6) /* advance_register register_index value32      */ \
+V(POP_CP,            10, 1) /* pop_cp                                       */ \
+V(POP_BT,            11, 1) /* pop_bt                                       */ \
+V(POP_REGISTER,      12, 2) /* pop_register register_index                  */ \
+V(FAIL,              13, 1) /* fail                                         */ \
+V(SUCCEED,           14, 1) /* succeed                                      */ \
+V(ADVANCE_CP,        15, 5) /* advance_cp offset32                          */ \
+V(GOTO,              16, 5) /* goto addr32                                  */ \
+V(LOAD_CURRENT_CHAR, 17, 9) /* load offset32 addr32                         */ \
+V(CHECK_CHAR,        18, 7) /* check_char uc16 addr32                       */ \
+V(CHECK_NOT_CHAR,    19, 7) /* check_not_char uc16 addr32                   */ \
+V(OR_CHECK_NOT_CHAR, 20, 9) /* or_check_not_char uc16 uc16 addr32           */ \
+V(MINUS_OR_CHECK_NOT_CHAR, 21, 9) /* minus_or_check_not_char uc16 uc16 ad...*/ \
+V(CHECK_LT,          22, 7) /* check_lt uc16 addr32                         */ \
+V(CHECK_GT,          23, 7) /* check_gr uc16 addr32                         */ \
+V(CHECK_NOT_BACK_REF, 24, 6) /* check_not_back_ref capture_idx addr32       */ \
+V(LOOKUP_MAP1,       25, 11) /* l_map1 start16 bit_map_addr32 addr32        */ \
+V(LOOKUP_MAP2,       26, 99) /* l_map2 start16 half_nibble_map_addr32*      */ \
+V(LOOKUP_MAP8,       27, 99) /* l_map8 start16 byte_map addr32*             */ \
+V(LOOKUP_HI_MAP8,    28, 99) /* l_himap8 start8 byte_map_addr32 addr32*     */ \
+V(CHECK_REGISTER_LT, 29, 8) /* check_reg_lt register_index value16 addr32   */ \
+V(CHECK_REGISTER_GE, 30, 8) /* check_reg_ge register_index value16 addr32   */ \
+
+#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
+} }
+
+#endif  // V8_BYTECODES_IRREGEXP_H_
index 13075f8..77c43bc 100644 (file)
@@ -237,12 +237,14 @@ template <int> class StaticAssertionHelper { };
 // The ASSERT macro is equivalent to CHECK except that it only
 // generates code in debug builds.  Ditto STATIC_ASSERT.
 #ifdef DEBUG
+#define ASSERT_RESULT(expr)  CHECK(expr)
 #define ASSERT(condition)    CHECK(condition)
 #define ASSERT_EQ(v1, v2)    CHECK_EQ(v1, v2)
 #define ASSERT_NE(v1, v2)   CHECK_NE(v1, v2)
 #define STATIC_ASSERT(test)  STATIC_CHECK(test)
 #define SLOW_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition)
 #else
+#define ASSERT_RESULT(expr)     (expr)
 #define ASSERT(condition)      ((void) 0)
 #define ASSERT_EQ(v1, v2)      ((void) 0)
 #define ASSERT_NE(v1, v2)     ((void) 0)
@@ -256,4 +258,6 @@ template <int> class StaticAssertionHelper { };
 
 #define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & kHeapObjectTagMask) == 0)
 
+#define ASSERT_NOT_NULL(p)  ASSERT_NE(NULL, p)
+
 #endif  // V8_CHECKS_H_
index c74708b..46ddb15 100644 (file)
@@ -120,7 +120,7 @@ typedef int32_t instr_t;
 // bits.
 //
 // bool InstructionSetsConditionCodes(byte* ptr) {
-//   Instr *instr = Instr::At(ptr);
+//   Instrinstr = Instr::At(ptr);
 //   int type = instr->TypeField();
 //   return ((type == 0) || (type == 1)) && instr->HasS();
 // }
index 209cd4d..2c82b1d 100644 (file)
@@ -170,9 +170,9 @@ Handle<Proxy> Factory::NewProxy(const AccessorDescriptor* desc) {
 }
 
 
-Handle<ByteArray> Factory::NewByteArray(int length) {
+Handle<ByteArray> Factory::NewByteArray(int length, PretenureFlag pretenure) {
   ASSERT(0 <= length);
-  CALL_HEAP_FUNCTION(Heap::AllocateByteArray(length), ByteArray);
+  CALL_HEAP_FUNCTION(Heap::AllocateByteArray(length, pretenure), ByteArray);
 }
 
 
@@ -458,8 +458,14 @@ Handle<JSFunction> Factory::NewFunctionWithPrototype(Handle<String> name,
 
 
 Handle<Code> Factory::NewCode(const CodeDesc& desc, ScopeInfo<>* sinfo,
+                              Code::Flags flags, Handle<Object> self_ref) {
+  CALL_HEAP_FUNCTION(Heap::CreateCode(
+      desc, sinfo, flags, reinterpret_cast<Code**>(self_ref.location())), Code);
+}
+
+Handle<Code> Factory::NewCode(const CodeDesc& desc, ScopeInfo<>* sinfo,
                               Code::Flags flags) {
-  CALL_HEAP_FUNCTION(Heap::CreateCode(desc, sinfo, flags), Code);
+  CALL_HEAP_FUNCTION(Heap::CreateCode(desc, sinfo, flags, NULL), Code);
 }
 
 
@@ -706,8 +712,11 @@ Handle<JSFunction> Factory::CreateApiFunction(
   ASSERT(type != INVALID_TYPE);
 
   Handle<JSFunction> result =
-      Factory::NewFunction(Factory::empty_symbol(), type, instance_size,
-                           code, true);
+      Factory::NewFunction(Factory::empty_symbol(),
+                           type,
+                           instance_size,
+                           code,
+                           true);
   // Set class name.
   Handle<Object> class_name = Handle<Object>(obj->class_name());
   if (class_name->IsString()) {
index 89e2d69..429c483 100644 (file)
@@ -147,7 +147,8 @@ class Factory : public AllStatic {
   // the old generation).
   static Handle<Proxy> NewProxy(const AccessorDescriptor* proxy);
 
-  static Handle<ByteArray> NewByteArray(int length);
+  static Handle<ByteArray> NewByteArray(int length,
+                                        PretenureFlag pretenure = NOT_TENURED);
 
   static Handle<Map> NewMap(InstanceType type, int instance_size);
 
@@ -206,6 +207,9 @@ class Factory : public AllStatic {
       Handle<Context> context);
 
   static Handle<Code> NewCode(const CodeDesc& desc, ScopeInfo<>* sinfo,
+                              Code::Flags flags, Handle<Object> self_reference);
+
+  static Handle<Code> NewCode(const CodeDesc& desc, ScopeInfo<>* sinfo,
                               Code::Flags flags);
 
   static Handle<Code> CopyCode(Handle<Code> code);
index 2c253db..59926ea 100644 (file)
@@ -289,6 +289,12 @@ DEFINE_bool(collect_heap_spill_statistics, false,
             "report heap spill statistics along with heap_stats "
             "(requires heap_stats)")
 
+DEFINE_bool(irregexp, false, "new regular expression code")
+DEFINE_bool(trace_regexps, false, "trace Irregexp execution")
+DEFINE_bool(trace_regexp_bytecodes, false, "trace Irregexp bytecode executon")
+DEFINE_bool(attempt_case_independent, false, "attempt to run Irregexp case independent")
+DEFINE_bool(irregexp_native, false, "use native code Irregexp implementation (IA32 only)")
+
 //
 // Logging and profiling only flags
 //
index 387ed88..69e9006 100644 (file)
@@ -178,10 +178,16 @@ class Map;
 class MapSpace;
 class MarkCompactCollector;
 class NewSpace;
+class NodeVisitor;
 class Object;
 class OldSpace;
 class Property;
 class Proxy;
+class RegExpNode;
+struct RegExpParseResult;
+class RegExpTree;
+class RegExpCompiler;
+class RegExpVisitor;
 class Scope;
 template<class Allocator = FreeStoreAllocationPolicy> class ScopeInfo;
 class Script;
index 804e525..53b0774 100644 (file)
@@ -392,8 +392,7 @@ void Heap::PerformGarbageCollection(AllocationSpace space,
   }
   Counters::objs_since_last_young.Set(0);
 
-  // Process weak handles post gc.
-  GlobalHandles::PostGarbageCollectionProcessing();
+  PostGarbageCollectionProcessing();
 
   if (collector == MARK_COMPACTOR) {
     // Register the amount of external allocated memory.
@@ -408,6 +407,14 @@ void Heap::PerformGarbageCollection(AllocationSpace space,
 }
 
 
+void Heap::PostGarbageCollectionProcessing() {
+  // Process weak handles post gc.
+  GlobalHandles::PostGarbageCollectionProcessing();
+  // Update flat string readers.
+  FlatStringReader::PostGarbageCollectionProcessing();
+}
+
+
 void Heap::MarkCompact(GCTracer* tracer) {
   gc_state_ = MARK_COMPACT;
   mc_count_++;
@@ -1582,6 +1589,24 @@ Object* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
 }
 
 
+Object* Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
+  if (pretenure == NOT_TENURED) {
+    return AllocateByteArray(length);
+  }
+  int size = ByteArray::SizeFor(length);
+  AllocationSpace space =
+      size > MaxHeapObjectSize() ? LO_SPACE : OLD_DATA_SPACE;
+
+  Object* result = AllocateRaw(size, space, OLD_DATA_SPACE);
+
+  if (result->IsFailure()) return result;
+
+  reinterpret_cast<Array*>(result)->set_map(byte_array_map());
+  reinterpret_cast<Array*>(result)->set_length(length);
+  return result;
+}
+
+
 Object* Heap::AllocateByteArray(int length) {
   int size = ByteArray::SizeFor(length);
   AllocationSpace space =
@@ -1599,7 +1624,8 @@ Object* Heap::AllocateByteArray(int length) {
 
 Object* Heap::CreateCode(const CodeDesc& desc,
                          ScopeInfo<>* sinfo,
-                         Code::Flags flags) {
+                         Code::Flags flags,
+                         Code** self_reference) {
   // Compute size
   int body_size = RoundUp(desc.instr_size + desc.reloc_size, kObjectAlignment);
   int sinfo_size = 0;
@@ -1622,7 +1648,16 @@ Object* Heap::CreateCode(const CodeDesc& desc,
   code->set_sinfo_size(sinfo_size);
   code->set_flags(flags);
   code->set_ic_flag(Code::IC_TARGET_IS_ADDRESS);
-  code->CopyFrom(desc);  // migrate generated code
+  // Allow self references to created code object.
+  if (self_reference != NULL) {
+    *self_reference = code;
+  }
+  // Migrate generated code.
+  // The generated code can contain Object** values (typically from handles)
+  // that are dereferenced during the copy to point directly to the actual heap
+  // objects. These pointers can include references to the code object itself,
+  // through the self_reference parameter.
+  code->CopyFrom(desc);
   if (sinfo != NULL) sinfo->Serialize(code);  // write scope info
 
 #ifdef DEBUG
index 694ee56..bbd679b 100644 (file)
@@ -391,7 +391,13 @@ class Heap : public AllStatic {
   // Allocate a byte array of the specified length
   // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
   // failed.
-  // Please not this does not perform a garbage collection.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateByteArray(int length, PretenureFlag pretenure);
+
+  // Allocate a non-tenured byte array of the specified length
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
   static Object* AllocateByteArray(int length);
 
   // Allocates a fixed array initialized with undefined values
@@ -549,11 +555,14 @@ class Heap : public AllStatic {
 
   // Makes a new native code object
   // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
-  // failed.
+  // failed. On success, the pointer to the Code object is stored in the
+  // self_reference. This allows generated code to reference its own Code
+  // object by containing this pointer.
   // Please note this function does not perform a garbage collection.
   static Object* CreateCode(const CodeDesc& desc,
                             ScopeInfo<>* sinfo,
-                            Code::Flags flags);
+                            Code::Flags flags,
+                            Code** self_reference = NULL);
 
   static Object* CopyCode(Code* code);
   // Finds the symbol for string in the symbol table.
@@ -582,6 +591,9 @@ class Heap : public AllStatic {
   static void GarbageCollectionPrologue();
   static void GarbageCollectionEpilogue();
 
+  // Code that should be executed after the garbage collection proper.
+  static void PostGarbageCollectionProcessing();
+
   // Performs garbage collection operation.
   // Returns whether required_space bytes are available after the collection.
   static bool CollectGarbage(int required_space, AllocationSpace space);
diff --git a/src/interpreter-irregexp.cc b/src/interpreter-irregexp.cc
new file mode 100644 (file)
index 0000000..7c915eb
--- /dev/null
@@ -0,0 +1,347 @@
+// Copyright 2008 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.
+
+// A simple interpreter for the Irregexp byte code.
+
+
+#include "v8.h"
+#include "utils.h"
+#include "ast.h"
+#include "bytecodes-irregexp.h"
+#include "interpreter-irregexp.h"
+
+
+namespace v8 { namespace internal {
+
+
+#ifdef DEBUG
+static void TraceInterpreter(const byte* code_base,
+                             const byte* pc,
+                             int stack_depth,
+                             int current_position,
+                             int bytecode_length,
+                             const char* bytecode_name) {
+  if (FLAG_trace_regexp_bytecodes) {
+    PrintF("pc = %02x, sp = %d, current = %d, bc = %s",
+            pc - code_base,
+            stack_depth,
+            current_position,
+            bytecode_name);
+    for (int i = 1; i < bytecode_length; i++) {
+      printf(", %02x", pc[i]);
+    }
+    printf("\n");
+  }
+}
+
+
+# define BYTECODE(name) case BC_##name:                                       \
+                          TraceInterpreter(code_base,                         \
+                                           pc,                                \
+                                           backtrack_sp - backtrack_stack,    \
+                                           current,                           \
+                                           BC_##name##_LENGTH,                \
+                                           #name);
+#else
+# define BYTECODE(name) case BC_##name:  // NOLINT
+#endif
+
+
+
+static bool RawMatch(const byte* code_base,
+                     Vector<const uc16> subject,
+                     int* registers,
+                     int current) {
+  const byte* pc = code_base;
+  static const int kBacktrackStackSize = 10000;
+  int backtrack_stack[kBacktrackStackSize];
+  int backtrack_stack_space = kBacktrackStackSize;
+  int* backtrack_sp = backtrack_stack;
+  int current_char = -1;
+#ifdef DEBUG
+  if (FLAG_trace_regexp_bytecodes) {
+    PrintF("\n\nStart bytecode interpreter\n\n");
+  }
+#endif
+  while (true) {
+    switch (*pc) {
+      BYTECODE(BREAK)
+        UNREACHABLE();
+        return false;
+      BYTECODE(PUSH_CP)
+        if (--backtrack_stack_space < 0) {
+          return false;  // No match on backtrack stack overflow.
+        }
+        *backtrack_sp++ = current + Load32(pc + 1);
+        pc += BC_PUSH_CP_LENGTH;
+        break;
+      BYTECODE(PUSH_BT)
+        if (--backtrack_stack_space < 0) {
+          return false;  // No match on backtrack stack overflow.
+        }
+        *backtrack_sp++ = Load32(pc + 1);
+        pc += BC_PUSH_BT_LENGTH;
+        break;
+      BYTECODE(PUSH_REGISTER)
+        if (--backtrack_stack_space < 0) {
+          return false;  // No match on backtrack stack overflow.
+        }
+        *backtrack_sp++ = registers[pc[1]];
+        pc += BC_PUSH_REGISTER_LENGTH;
+        break;
+      BYTECODE(SET_REGISTER)
+        registers[pc[1]] = Load32(pc + 2);
+        pc += BC_SET_REGISTER_LENGTH;
+        break;
+      BYTECODE(ADVANCE_REGISTER)
+        registers[pc[1]] += Load32(pc + 2);
+        pc += BC_ADVANCE_REGISTER_LENGTH;
+        break;
+      BYTECODE(SET_REGISTER_TO_CP)
+        registers[pc[1]] = current + Load32(pc + 2);
+        pc += BC_SET_REGISTER_TO_CP_LENGTH;
+        break;
+      BYTECODE(SET_CP_TO_REGISTER)
+        current = registers[pc[1]];
+        pc += BC_SET_CP_TO_REGISTER_LENGTH;
+        break;
+      BYTECODE(SET_REGISTER_TO_SP)
+        registers[pc[1]] = backtrack_sp - backtrack_stack;
+        pc += BC_SET_REGISTER_TO_SP_LENGTH;
+        break;
+      BYTECODE(SET_SP_TO_REGISTER)
+        backtrack_sp = backtrack_stack + registers[pc[1]];
+        backtrack_stack_space = kBacktrackStackSize -
+                                (backtrack_sp - backtrack_stack);
+        pc += BC_SET_SP_TO_REGISTER_LENGTH;
+        break;
+      BYTECODE(POP_CP)
+        backtrack_stack_space++;
+        --backtrack_sp;
+        current = *backtrack_sp;
+        pc += BC_POP_CP_LENGTH;
+        break;
+      BYTECODE(POP_BT)
+        backtrack_stack_space++;
+        --backtrack_sp;
+        pc = code_base + *backtrack_sp;
+        break;
+      BYTECODE(POP_REGISTER)
+        backtrack_stack_space++;
+        --backtrack_sp;
+        registers[pc[1]] = *backtrack_sp;
+        pc += BC_POP_REGISTER_LENGTH;
+        break;
+      BYTECODE(FAIL)
+        return false;
+      BYTECODE(SUCCEED)
+        return true;
+      BYTECODE(ADVANCE_CP)
+        current += Load32(pc + 1);
+        pc += BC_ADVANCE_CP_LENGTH;
+        break;
+      BYTECODE(GOTO)
+        pc = code_base + Load32(pc + 1);
+        break;
+      BYTECODE(LOAD_CURRENT_CHAR) {
+        int pos = current + Load32(pc + 1);
+        if (pos >= subject.length()) {
+          pc = code_base + Load32(pc + 5);
+        } else {
+          current_char = subject[pos];
+          pc += BC_LOAD_CURRENT_CHAR_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_CHAR) {
+        int c = Load16(pc + 1);
+        if (c == current_char) {
+          pc = code_base + Load32(pc + 3);
+        } else {
+          pc += BC_CHECK_CHAR_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_NOT_CHAR) {
+        int c = Load16(pc + 1);
+        if (c != current_char) {
+          pc = code_base + Load32(pc + 3);
+        } else {
+          pc += BC_CHECK_NOT_CHAR_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(OR_CHECK_NOT_CHAR) {
+        int c = Load16(pc + 1);
+        if (c != (current_char | Load16(pc + 3))) {
+          pc = code_base + Load32(pc + 5);
+        } else {
+          pc += BC_OR_CHECK_NOT_CHAR_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(MINUS_OR_CHECK_NOT_CHAR) {
+        int c = Load16(pc + 1);
+        int m = Load16(pc + 3);
+        if (c != ((current_char - m) | m)) {
+          pc = code_base + Load32(pc + 5);
+        } else {
+          pc += BC_MINUS_OR_CHECK_NOT_CHAR_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_LT) {
+        int limit = Load16(pc + 1);
+        if (current_char < limit) {
+          pc = code_base + Load32(pc + 3);
+        } else {
+          pc += BC_CHECK_LT_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_GT) {
+        int limit = Load16(pc + 1);
+        if (current_char > limit) {
+          pc = code_base + Load32(pc + 3);
+        } else {
+          pc += BC_CHECK_GT_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_REGISTER_LT)
+        if (registers[pc[1]] < Load16(pc + 2)) {
+          pc = code_base + Load32(pc + 4);
+        } else {
+          pc += BC_CHECK_REGISTER_LT_LENGTH;
+        }
+        break;
+      BYTECODE(CHECK_REGISTER_GE)
+        if (registers[pc[1]] >= Load16(pc + 2)) {
+          pc = code_base + Load32(pc + 4);
+        } else {
+          pc += BC_CHECK_REGISTER_GE_LENGTH;
+        }
+        break;
+      BYTECODE(LOOKUP_MAP1) {
+        // Look up character in a bitmap.  If we find a 0, then jump to the
+        // location at pc + 7.  Otherwise fall through!
+        int index = current_char - Load16(pc + 1);
+        byte map = code_base[Load32(pc + 3) + (index >> 3)];
+        map = ((map >> (index & 7)) & 1);
+        if (map == 0) {
+          pc = code_base + Load32(pc + 7);
+        } else {
+          pc += BC_LOOKUP_MAP1_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(LOOKUP_MAP2) {
+        // Look up character in a half-nibble map.  If we find 00, then jump to
+        // the location at pc + 7.   If we find 01 then jump to location at
+        // pc + 11, etc.
+        int index = (current_char - Load16(pc + 1)) << 1;
+        byte map = code_base[Load32(pc + 3) + (index >> 3)];
+        map = ((map >> (index & 7)) & 3);
+        if (map < 2) {
+          if (map == 0) {
+            pc = code_base + Load32(pc + 7);
+          } else {
+            pc = code_base + Load32(pc + 11);
+          }
+        } else {
+          if (map == 2) {
+            pc = code_base + Load32(pc + 15);
+          } else {
+            pc = code_base + Load32(pc + 19);
+          }
+        }
+        break;
+      }
+      BYTECODE(LOOKUP_MAP8) {
+        // Look up character in a byte map.  Use the byte as an index into a
+        // table that follows this instruction immediately.
+        int index = current_char - Load16(pc + 1);
+        byte map = code_base[Load32(pc + 3) + index];
+        const byte* new_pc = code_base + Load32(pc + 7) + (map << 2);
+        pc = code_base + Load32(new_pc);
+        break;
+      }
+      BYTECODE(LOOKUP_HI_MAP8) {
+        // Look up high byte of this character in a byte map.  Use the byte as
+        // an index into a table that follows this instruction immediately.
+        int index = (current_char >> 8) - pc[1];
+        byte map = code_base[Load32(pc + 2) + index];
+        const byte* new_pc = code_base + Load32(pc + 6) + (map << 2);
+        pc = code_base + Load32(new_pc);
+        break;
+      }
+      BYTECODE(CHECK_NOT_BACK_REF) {
+        int from = registers[pc[1]];
+        int len = registers[pc[1] + 1] - from;
+        if (current + len > subject.length()) {
+          pc = code_base + Load32(pc + 2);
+          break;
+        } else {
+          int i;
+          for (i = 0; i < len; i++) {
+            if (subject[from + i] != subject[current + i]) {
+              pc = code_base + Load32(pc + 2);
+              break;
+            }
+          }
+          if (i < len) break;
+          current += len;
+        }
+        pc += BC_CHECK_NOT_BACK_REF_LENGTH;
+        break;
+      }
+      default:
+        UNREACHABLE();
+        break;
+    }
+  }
+}
+
+
+bool IrregexpInterpreter::Match(Handle<ByteArray> code_array,
+                                Handle<String> subject16,
+                                int* registers,
+                                int start_position) {
+  ASSERT(StringShape(*subject16).IsTwoByteRepresentation());
+  ASSERT(subject16->IsFlat(StringShape(*subject16)));
+
+
+  AssertNoAllocation a;
+  const byte* code_base = code_array->GetDataStartAddress();
+  return RawMatch(code_base,
+                  Vector<const uc16>(subject16->GetTwoByteData(),
+                                     subject16->length()),
+                  registers,
+                  start_position);
+}
+
+} }  // namespace v8::internal
diff --git a/src/interpreter-irregexp.h b/src/interpreter-irregexp.h
new file mode 100644 (file)
index 0000000..ee8d440
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2008 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.
+
+// A simple interpreter for the Regexp2000 byte code.
+
+#ifndef V8_INTERPRETER_IRREGEXP_H_
+#define V8_INTERPRETER_IRREGEXP_H_
+
+namespace v8 { namespace internal {
+
+
+class IrregexpInterpreter {
+ public:
+  static bool Match(Handle<ByteArray> code,
+                    Handle<String> subject16,
+                    int* captures,
+                    int start_position);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_INTERPRETER_IRREGEXP_H_
diff --git a/src/jsregexp-inl.h b/src/jsregexp-inl.h
new file mode 100644 (file)
index 0000000..ec3b5ee
--- /dev/null
@@ -0,0 +1,266 @@
+// Copyright 2006-2008 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_INL_H_
+#define V8_JSREGEXP_INL_H_
+
+
+#include "jsregexp.h"
+#include "regexp-macro-assembler.h"
+
+
+namespace v8 {
+namespace internal {
+
+
+template <typename C>
+bool ZoneSplayTree<C>::Insert(const Key& key, Locator* locator) {
+  if (is_empty()) {
+    // If the tree is empty, insert the new node.
+    root_ = new Node(key, C::kNoValue);
+  } else {
+    // Splay on the key to move the last node on the search path
+    // for the key to the root of the tree.
+    Splay(key);
+    // Ignore repeated insertions with the same key.
+    int cmp = C::Compare(key, root_->key_);
+    if (cmp == 0) {
+      locator->bind(root_);
+      return false;
+    }
+    // Insert the new node.
+    Node* node = new Node(key, C::kNoValue);
+    if (cmp > 0) {
+      node->left_ = root_;
+      node->right_ = root_->right_;
+      root_->right_ = NULL;
+    } else {
+      node->right_ = root_;
+      node->left_ = root_->left_;
+      root_->left_ = NULL;
+    }
+    root_ = node;
+  }
+  locator->bind(root_);
+  return true;
+}
+
+
+template <typename C>
+bool ZoneSplayTree<C>::Find(const Key& key, Locator* locator) {
+  if (is_empty())
+    return false;
+  Splay(key);
+  if (C::Compare(key, root_->key_) == 0) {
+    locator->bind(root_);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+
+template <typename C>
+bool ZoneSplayTree<C>::FindGreatestLessThan(const Key& key,
+                                            Locator* locator) {
+  if (is_empty())
+    return false;
+  // Splay on the key to move the node with the given key or the last
+  // node on the search path to the top of the tree.
+  Splay(key);
+  // Now the result is either the root node or the greatest node in
+  // the left subtree.
+  int cmp = C::Compare(root_->key_, key);
+  if (cmp <= 0) {
+    locator->bind(root_);
+    return true;
+  } else {
+    Node* temp = root_;
+    root_ = root_->left_;
+    bool result = FindGreatest(locator);
+    root_ = temp;
+    return result;
+  }
+}
+
+
+template <typename C>
+bool ZoneSplayTree<C>::FindLeastGreaterThan(const Key& key,
+                                            Locator* locator) {
+  if (is_empty())
+    return false;
+  // Splay on the key to move the node with the given key or the last
+  // node on the search path to the top of the tree.
+  Splay(key);
+  // Now the result is either the root node or the least node in
+  // the right subtree.
+  int cmp = C::Compare(root_->key_, key);
+  if (cmp >= 0) {
+    locator->bind(root_);
+    return true;
+  } else {
+    Node* temp = root_;
+    root_ = root_->right_;
+    bool result = FindLeast(locator);
+    root_ = temp;
+    return result;
+  }
+}
+
+
+template <typename C>
+bool ZoneSplayTree<C>::FindGreatest(Locator* locator) {
+  if (is_empty())
+    return false;
+  Node* current = root_;
+  while (current->right_ != NULL)
+    current = current->right_;
+  locator->bind(current);
+  return true;
+}
+
+
+template <typename C>
+bool ZoneSplayTree<C>::FindLeast(Locator* locator) {
+  if (is_empty())
+    return false;
+  Node* current = root_;
+  while (current->left_ != NULL)
+    current = current->left_;
+  locator->bind(current);
+  return true;
+}
+
+
+template <typename C>
+bool ZoneSplayTree<C>::Remove(const Key& key) {
+  // Bail if the tree is empty
+  if (is_empty())
+    return false;
+  // Splay on the key to move the node with the given key to the top.
+  Splay(key);
+  // Bail if the key is not in the tree
+  if (C::Compare(key, root_->key_) != 0)
+    return false;
+  if (root_->left_ == NULL) {
+    // No left child, so the new tree is just the right child.
+    root_ = root_->right_;
+  } else {
+    // Left child exists.
+    Node* right = root_->right_;
+    // Make the original left child the new root.
+    root_ = root_->left_;
+    // Splay to make sure that the new root has an empty right child.
+    Splay(key);
+    // Insert the original right child as the right child of the new
+    // root.
+    root_->right_ = right;
+  }
+  return true;
+}
+
+
+template <typename C>
+void ZoneSplayTree<C>::Splay(const Key& key) {
+  if (is_empty())
+    return;
+  Node dummy_node(C::kNoKey, C::kNoValue);
+  // Create a dummy node.  The use of the dummy node is a bit
+  // counter-intuitive: The right child of the dummy node will hold
+  // the L tree of the algorithm.  The left child of the dummy node
+  // will hold the R tree of the algorithm.  Using a dummy node, left
+  // and right will always be nodes and we avoid special cases.
+  Node* dummy = &dummy_node;
+  Node* left = dummy;
+  Node* right = dummy;
+  Node* current = root_;
+  while (true) {
+    int cmp = C::Compare(key, current->key_);
+    if (cmp < 0) {
+      if (current->left_ == NULL)
+        break;
+      if (C::Compare(key, current->left_->key_) < 0) {
+        // Rotate right.
+        Node* temp = current->left_;
+        current->left_ = temp->right_;
+        temp->right_ = current;
+        current = temp;
+        if (current->left_ == NULL)
+          break;
+      }
+      // Link right.
+      right->left_ = current;
+      right = current;
+      current = current->left_;
+    } else if (cmp > 0) {
+      if (current->right_ == NULL)
+        break;
+      if (C::Compare(key, current->right_->key_) > 0) {
+        // Rotate left.
+        Node* temp = current->right_;
+        current->right_ = temp->left_;
+        temp->left_ = current;
+        current = temp;
+        if (current->right_ == NULL)
+          break;
+      }
+      // Link left.
+      left->right_ = current;
+      left = current;
+      current = current->right_;
+    } else {
+      break;
+    }
+  }
+  // Assemble.
+  left->right_ = current->left_;
+  right->left_ = current->right_;
+  current->left_ = dummy->right_;
+  current->right_ = dummy->left_;
+  root_ = current;
+}
+
+
+template <typename Node, class Callback>
+static void DoForEach(Node* node, Callback* callback) {
+  if (node == NULL) return;
+  DoForEach<Node, Callback>(node->left(), callback);
+  callback->Call(node->key(), node->value());
+  DoForEach<Node, Callback>(node->right(), callback);
+}
+
+
+void RegExpNode::Bind(RegExpMacroAssembler* macro) {
+  macro->Bind(&label_);
+}
+
+
+}  // namespace internal
+}  // namespace v8
+
+
+#endif  // V8_JSREGEXP_INL_H_
index cacf5ed..7e25ea8 100644 (file)
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#define _HAS_EXCEPTIONS 0
+#include <set>
+
 #include "v8.h"
 
+#include "ast.h"
 #include "execution.h"
 #include "factory.h"
-#include "jsregexp.h"
+#include "jsregexp-inl.h"
 #include "platform.h"
 #include "runtime.h"
 #include "top.h"
 #include "compilation-cache.h"
+#include "string-stream.h"
+#include "parser.h"
+#include "assembler-irregexp.h"
+#include "regexp-macro-assembler.h"
+#include "regexp-macro-assembler-irregexp.h"
+#if defined __arm__ || defined __thumb__ || defined ARM
+// include regexp-macro-assembler-arm.h when created.
+#else  // ia32
+#include "regexp-macro-assembler-ia32.h"
+#endif
+#include "interpreter-irregexp.h"
 
 // Including pcre.h undefines DEBUG to avoid getting debug output from
 // the JSCRE implementation. Make sure to redefine it in debug mode
 #include "third_party/jscre/pcre.h"
 #endif
 
-namespace v8 { namespace internal {
 
+namespace v8 { namespace internal {
 
-#define CAPTURE_INDEX 0
-#define INTERNAL_INDEX 1
 
 static Failure* malloc_failure;
 
@@ -176,7 +189,16 @@ static JSRegExp::Flags RegExpFlagsFromString(Handle<String> str) {
 }
 
 
-unibrow::Predicate<unibrow::RegExpSpecialChar, 128> is_reg_exp_special_char;
+static inline void ThrowRegExpException(Handle<JSRegExp> re,
+                                        Handle<String> pattern,
+                                        Handle<String> error_text,
+                                        const char* message) {
+  Handle<JSArray> array = Factory::NewJSArray(2);
+  SetElement(array, 0, pattern);
+  SetElement(array, 1, error_text);
+  Handle<Object> regexp_err = Factory::NewSyntaxError(message, array);
+  Top::Throw(*regexp_err);
+}
 
 
 Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
@@ -186,20 +208,42 @@ Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
   Handle<FixedArray> cached = CompilationCache::LookupRegExp(pattern, flags);
   bool in_cache = !cached.is_null();
   Handle<Object> result;
-  StringShape shape(*pattern);
   if (in_cache) {
     re->set_data(*cached);
     result = re;
   } else {
-    bool is_atom = !flags.is_ignore_case();
-    for (int i = 0; is_atom && i < pattern->length(shape); i++) {
-      if (is_reg_exp_special_char.get(pattern->Get(shape, i)))
-        is_atom = false;
+    FlattenString(pattern);
+    RegExpParseResult parse_result;
+    FlatStringReader reader(pattern);
+    if (!ParseRegExp(&reader, &parse_result)) {
+      // Throw an exception if we fail to parse the pattern.
+      ThrowRegExpException(re,
+                           pattern,
+                           parse_result.error,
+                           "malformed_regexp");
+      return Handle<Object>();
     }
-    if (is_atom) {
-      result = AtomCompile(re, pattern, flags);
+    RegExpAtom* atom = parse_result.tree->AsAtom();
+    if (atom != NULL && !flags.is_ignore_case()) {
+      if (parse_result.has_character_escapes) {
+        Vector<const uc16> atom_pattern = atom->data();
+        Handle<String> atom_string =
+            Factory::NewStringFromTwoByte(atom_pattern);
+        result = AtomCompile(re, pattern, flags, atom_string);
+      } else {
+        result = AtomCompile(re, pattern, flags, pattern);
+      }
     } else {
-      result = JsreCompile(re, pattern, flags);
+      RegExpNode* node = NULL;
+      Handle<FixedArray> irregexp_data =
+          RegExpEngine::Compile(&parse_result,
+                                &node,
+                                flags.is_ignore_case());
+      if (irregexp_data.is_null()) {
+        result = JscrePrepare(re, pattern, flags);
+      } else {
+        result = IrregexpPrepare(re, pattern, flags, irregexp_data);
+      }
     }
     Object* data = re->data();
     if (data->IsFixedArray()) {
@@ -220,9 +264,11 @@ Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp,
                                 Handle<Object> index) {
   switch (regexp->TypeTag()) {
     case JSRegExp::JSCRE:
-      return JsreExec(regexp, subject, index);
+      return JscreExec(regexp, subject, index);
     case JSRegExp::ATOM:
       return AtomExec(regexp, subject, index);
+    case JSRegExp::IRREGEXP:
+      return IrregexpExec(regexp, subject, index);
     default:
       UNREACHABLE();
       return Handle<Object>();
@@ -234,9 +280,11 @@ Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp,
                                 Handle<String> subject) {
   switch (regexp->TypeTag()) {
     case JSRegExp::JSCRE:
-      return JsreExecGlobal(regexp, subject);
+      return JscreExecGlobal(regexp, subject);
     case JSRegExp::ATOM:
       return AtomExecGlobal(regexp, subject);
+    case JSRegExp::IRREGEXP:
+      return IrregexpExecGlobal(regexp, subject);
     default:
       UNREACHABLE();
       return Handle<Object>();
@@ -246,8 +294,9 @@ Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp,
 
 Handle<Object> RegExpImpl::AtomCompile(Handle<JSRegExp> re,
                                        Handle<String> pattern,
-                                       JSRegExp::Flags flags) {
-  Factory::SetRegExpData(re, JSRegExp::ATOM, pattern, flags, pattern);
+                                       JSRegExp::Flags flags,
+                                       Handle<String> match_pattern) {
+  Factory::SetRegExpData(re, JSRegExp::ATOM, pattern, flags, match_pattern);
   return re;
 }
 
@@ -267,12 +316,8 @@ Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re,
   if (value == -1) return Factory::null_value();
 
   Handle<FixedArray> array = Factory::NewFixedArray(2);
-  array->set(0,
-             Smi::FromInt(value),
-             SKIP_WRITE_BARRIER);
-  array->set(1,
-             Smi::FromInt(value + needle->length()),
-             SKIP_WRITE_BARRIER);
+  array->set(0, Smi::FromInt(value));
+  array->set(1, Smi::FromInt(value + needle->length()));
   return Factory::NewJSArrayWithElements(array);
 }
 
@@ -296,12 +341,8 @@ Handle<Object> RegExpImpl::AtomExecGlobal(Handle<JSRegExp> re,
     int end = value + needle_length;
 
     Handle<FixedArray> array = Factory::NewFixedArray(2);
-    array->set(0,
-               Smi::FromInt(value),
-               SKIP_WRITE_BARRIER);
-    array->set(1,
-               Smi::FromInt(end),
-               SKIP_WRITE_BARRIER);
+    array->set(0, Smi::FromInt(value));
+    array->set(1, Smi::FromInt(end));
     Handle<JSArray> pair = Factory::NewJSArrayWithElements(array);
     SetElement(result, match_count, pair);
     match_count++;
@@ -312,6 +353,24 @@ Handle<Object> RegExpImpl::AtomExecGlobal(Handle<JSRegExp> re,
 }
 
 
+Handle<Object>RegExpImpl::JscrePrepare(Handle<JSRegExp> re,
+                                       Handle<String> pattern,
+                                       JSRegExp::Flags flags) {
+  Handle<Object> value(Heap::undefined_value());
+  Factory::SetRegExpData(re, JSRegExp::JSCRE, pattern, flags, value);
+  return re;
+}
+
+
+Handle<Object>RegExpImpl::IrregexpPrepare(Handle<JSRegExp> re,
+                                          Handle<String> pattern,
+                                          JSRegExp::Flags flags,
+                                          Handle<FixedArray> irregexp_data) {
+  Factory::SetRegExpData(re, JSRegExp::IRREGEXP, pattern, flags, irregexp_data);
+  return re;
+}
+
+
 static inline Object* DoCompile(String* pattern,
                                 JSRegExp::Flags flags,
                                 unsigned* number_of_captures,
@@ -358,9 +417,13 @@ void CompileWithRetryAfterGC(Handle<String> pattern,
 }
 
 
-Handle<Object> RegExpImpl::JsreCompile(Handle<JSRegExp> re,
-                                       Handle<String> pattern,
-                                       JSRegExp::Flags flags) {
+Handle<Object> RegExpImpl::JscreCompile(Handle<JSRegExp> re) {
+  ASSERT_EQ(re->TypeTag(), JSRegExp::JSCRE);
+  ASSERT(re->DataAt(JSRegExp::kJscreDataIndex)->IsUndefined());
+
+  Handle<String> pattern(re->Pattern());
+  JSRegExp::Flags flags = re->GetFlags();
+
   Handle<String> two_byte_pattern = StringToTwoByte(pattern);
 
   unsigned number_of_captures;
@@ -391,26 +454,110 @@ Handle<Object> RegExpImpl::JsreCompile(Handle<JSRegExp> re,
   Handle<ByteArray> internal(
       ByteArray::FromDataStartAddress(reinterpret_cast<Address>(code)));
 
-  Handle<FixedArray> value = Factory::NewFixedArray(2);
-  value->set(CAPTURE_INDEX, Smi::FromInt(number_of_captures));
-  value->set(INTERNAL_INDEX, *internal);
+  Handle<FixedArray> value = Factory::NewFixedArray(kJscreDataLength);
+  value->set(kJscreNumberOfCapturesIndex, Smi::FromInt(number_of_captures));
+  value->set(kJscreInternalIndex, *internal);
   Factory::SetRegExpData(re, JSRegExp::JSCRE, pattern, flags, value);
 
   return re;
 }
 
 
-Handle<Object> RegExpImpl::JsreExecOnce(Handle<JSRegExp> regexp,
-                                        int num_captures,
-                                        Handle<String> subject,
-                                        int previous_index,
-                                        const uc16* two_byte_subject,
-                                        int* offsets_vector,
-                                        int offsets_vector_length) {
+Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<JSRegExp> regexp,
+                                            int num_captures,
+                                            Handle<String> two_byte_subject,
+                                            int previous_index,
+                                            int* offsets_vector,
+                                            int offsets_vector_length) {
+#ifdef DEBUG
+  if (FLAG_trace_regexp_bytecodes) {
+    String* pattern = regexp->Pattern();
+    PrintF("\n\nRegexp match:   /%s/\n\n", *(pattern->ToCString()));
+    PrintF("\n\nSubject string: '%s'\n\n", *(two_byte_subject->ToCString()));
+  }
+#endif
+  ASSERT(StringShape(*two_byte_subject).IsTwoByteRepresentation());
+  ASSERT(two_byte_subject->IsFlat(StringShape(*two_byte_subject)));
+  bool rc;
+  {
+    for (int i = (num_captures + 1) * 2 - 1; i >= 0; i--) {
+      offsets_vector[i] = -1;
+    }
+
+    LOG(RegExpExecEvent(regexp, previous_index, two_byte_subject));
+
+    FixedArray* irregexp =
+        FixedArray::cast(regexp->DataAt(JSRegExp::kIrregexpDataIndex));
+    int tag = Smi::cast(irregexp->get(kIrregexpImplementationIndex))->value();
+
+    switch (tag) {
+    case RegExpMacroAssembler::kIA32Implementation: {
+      Code* code = Code::cast(irregexp->get(kIrregexpCodeIndex));
+      SmartPointer<int> captures(NewArray<int>((num_captures + 1) * 2));
+      Address start_addr =
+          Handle<SeqTwoByteString>::cast(two_byte_subject)->GetCharsAddress();
+      int start_offset =
+          start_addr - reinterpret_cast<Address>(*two_byte_subject);
+      int end_offset =
+          start_offset + (two_byte_subject->length() - previous_index) * 2;
+      typedef bool testfunc(String**, int, int, int*);
+      testfunc* test = FUNCTION_CAST<testfunc*>(code->entry());
+      rc = test(two_byte_subject.location(),
+                start_offset,
+                end_offset,
+                *captures);
+      if (rc) {
+        // Capture values are relative to start_offset only.
+        for (int i = 0; i < offsets_vector_length; i++) {
+          if (offsets_vector[i] >= 0) {
+            offsets_vector[i] += previous_index;
+          }
+        }
+      }
+      break;
+    }
+    default:
+    case RegExpMacroAssembler::kARMImplementation:
+      UNREACHABLE();
+      rc = false;
+      break;
+    case RegExpMacroAssembler::kBytecodeImplementation: {
+      Handle<ByteArray> byte_codes = IrregexpCode(regexp);
+
+      rc = IrregexpInterpreter::Match(byte_codes,
+                                      two_byte_subject,
+                                      offsets_vector,
+                                      previous_index);
+      break;
+    }
+    }
+  }
+
+  if (!rc) {
+    return Factory::null_value();
+  }
+
+  Handle<FixedArray> array = Factory::NewFixedArray(2 * (num_captures+1));
+  // The captures come in (start, end+1) pairs.
+  for (int i = 0; i < 2 * (num_captures+1); i += 2) {
+    array->set(i, Smi::FromInt(offsets_vector[i]));
+    array->set(i+1, Smi::FromInt(offsets_vector[i+1]));
+  }
+  return Factory::NewJSArrayWithElements(array);
+}
+
+
+Handle<Object> RegExpImpl::JscreExecOnce(Handle<JSRegExp> regexp,
+                                         int num_captures,
+                                         Handle<String> subject,
+                                         int previous_index,
+                                         const uc16* two_byte_subject,
+                                         int* offsets_vector,
+                                         int offsets_vector_length) {
   int rc;
   {
     AssertNoAllocation a;
-    ByteArray* internal = JsreInternal(regexp);
+    ByteArray* internal = JscreInternal(regexp);
     const JscreRegExp* js_regexp =
         reinterpret_cast<JscreRegExp*>(internal->GetDataStartAddress());
 
@@ -444,12 +591,8 @@ Handle<Object> RegExpImpl::JsreExecOnce(Handle<JSRegExp> regexp,
   Handle<FixedArray> array = Factory::NewFixedArray(2 * (num_captures+1));
   // The captures come in (start, end+1) pairs.
   for (int i = 0; i < 2 * (num_captures+1); i += 2) {
-    array->set(i,
-               Smi::FromInt(offsets_vector[i]),
-               SKIP_WRITE_BARRIER);
-    array->set(i+1,
-               Smi::FromInt(offsets_vector[i+1]),
-               SKIP_WRITE_BARRIER);
+    array->set(i, Smi::FromInt(offsets_vector[i]));
+    array->set(i+1, Smi::FromInt(offsets_vector[i+1]));
   }
   return Factory::NewJSArrayWithElements(array);
 }
@@ -457,8 +600,8 @@ Handle<Object> RegExpImpl::JsreExecOnce(Handle<JSRegExp> regexp,
 
 class OffsetsVector {
  public:
-  inline OffsetsVector(int num_captures) {
-    offsets_vector_length_ = (num_captures + 1) * 3;
+  inline OffsetsVector(int num_registers) :
+    offsets_vector_length_(num_registers) {
     if (offsets_vector_length_ > kStaticOffsetsVectorSize) {
       vector_ = NewArray<int>(offsets_vector_length_);
     } else {
@@ -487,7 +630,7 @@ class OffsetsVector {
  private:
   int* vector_;
   int offsets_vector_length_;
-  static const int kStaticOffsetsVectorSize = 30;
+  static const int kStaticOffsetsVectorSize = 50;
   static int static_offsets_vector_[kStaticOffsetsVectorSize];
 };
 
@@ -496,33 +639,126 @@ int OffsetsVector::static_offsets_vector_[
     OffsetsVector::kStaticOffsetsVectorSize];
 
 
-Handle<Object> RegExpImpl::JsreExec(Handle<JSRegExp> regexp,
+Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> regexp,
                                     Handle<String> subject,
                                     Handle<Object> index) {
+  ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
+  ASSERT(!regexp->DataAt(JSRegExp::kIrregexpDataIndex)->IsUndefined());
+
   // Prepare space for the return values.
-  int num_captures = JsreCapture(regexp);
+  int number_of_registers = IrregexpNumberOfRegisters(regexp);
+  OffsetsVector offsets(number_of_registers);
+
+  int num_captures = IrregexpNumberOfCaptures(regexp);
+
+  int previous_index = static_cast<int>(DoubleToInteger(index->Number()));
+
+  Handle<String> subject16 = CachedStringToTwoByte(subject);
+
+  Handle<Object> result(
+      IrregexpExecOnce(regexp,
+                       num_captures,
+                       subject16,
+                       previous_index,
+                       offsets.vector(),
+                       offsets.length()));
+  return result;
+}
+
+
+Handle<Object> RegExpImpl::JscreExec(Handle<JSRegExp> regexp,
+                                     Handle<String> subject,
+                                     Handle<Object> index) {
+  ASSERT_EQ(regexp->TypeTag(), JSRegExp::JSCRE);
+  if (regexp->DataAt(JSRegExp::kJscreDataIndex)->IsUndefined()) {
+    Handle<Object> compile_result = JscreCompile(regexp);
+    if (compile_result.is_null()) return compile_result;
+  }
+  ASSERT(regexp->DataAt(JSRegExp::kJscreDataIndex)->IsFixedArray());
 
-  OffsetsVector offsets(num_captures);
+  int num_captures = JscreNumberOfCaptures(regexp);
+
+  OffsetsVector offsets((num_captures + 1) * 3);
 
   int previous_index = static_cast<int>(DoubleToInteger(index->Number()));
 
   Handle<String> subject16 = CachedStringToTwoByte(subject);
 
-  Handle<Object> result(JsreExecOnce(regexp, num_captures, subject,
-                                     previous_index,
-                                     subject16->GetTwoByteData(),
-                                     offsets.vector(), offsets.length()));
+  Handle<Object> result(JscreExecOnce(regexp,
+                                      num_captures,
+                                      subject,
+                                      previous_index,
+                                      subject16->GetTwoByteData(),
+                                      offsets.vector(),
+                                      offsets.length()));
 
   return result;
 }
 
 
-Handle<Object> RegExpImpl::JsreExecGlobal(Handle<JSRegExp> regexp,
-                                          Handle<String> subject) {
+Handle<Object> RegExpImpl::IrregexpExecGlobal(Handle<JSRegExp> regexp,
+                                              Handle<String> subject) {
+  ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
+  ASSERT(!regexp->DataAt(JSRegExp::kIrregexpDataIndex)->IsUndefined());
+
+  // Prepare space for the return values.
+  int number_of_registers = IrregexpNumberOfRegisters(regexp);
+  OffsetsVector offsets(number_of_registers);
+
+  int previous_index = 0;
+
+  Handle<JSArray> result = Factory::NewJSArray(0);
+  int i = 0;
+  Handle<Object> matches;
+
+  Handle<String> subject16 = CachedStringToTwoByte(subject);
+
+  do {
+    if (previous_index > subject->length() || previous_index < 0) {
+      // Per ECMA-262 15.10.6.2, if the previous index is greater than the
+      // string length, there is no match.
+      matches = Factory::null_value();
+    } else {
+      matches = IrregexpExecOnce(regexp,
+                                 IrregexpNumberOfCaptures(regexp),
+                                 subject16,
+                                 previous_index,
+                                 offsets.vector(),
+                                 offsets.length());
+
+      if (matches->IsJSArray()) {
+        SetElement(result, i, matches);
+        i++;
+        previous_index = offsets.vector()[1];
+        if (offsets.vector()[0] == offsets.vector()[1]) {
+          previous_index++;
+        }
+      }
+    }
+  } while (matches->IsJSArray());
+
+  // If we exited the loop with an exception, throw it.
+  if (matches->IsNull()) {  // Exited loop normally.
+    return result;
+  } else {  // Exited loop with the exception in matches.
+    return matches;
+  }
+}
+
+
+Handle<Object> RegExpImpl::JscreExecGlobal(Handle<JSRegExp> regexp,
+                                           Handle<String> subject) {
+  ASSERT_EQ(regexp->TypeTag(), JSRegExp::JSCRE);
+  if (regexp->DataAt(JSRegExp::kJscreDataIndex)->IsUndefined()) {
+    Handle<Object> compile_result = JscreCompile(regexp);
+    if (compile_result.is_null()) return compile_result;
+  }
+  ASSERT(regexp->DataAt(JSRegExp::kJscreDataIndex)->IsFixedArray());
+
   // Prepare space for the return values.
-  int num_captures = JsreCapture(regexp);
+  int num_captures = JscreNumberOfCaptures(regexp);
 
-  OffsetsVector offsets(num_captures);
+  OffsetsVector offsets((num_captures + 1) * 3);
 
   int previous_index = 0;
 
@@ -538,9 +774,13 @@ Handle<Object> RegExpImpl::JsreExecGlobal(Handle<JSRegExp> regexp,
       // string length, there is no match.
       matches = Factory::null_value();
     } else {
-      matches = JsreExecOnce(regexp, num_captures, subject, previous_index,
-                             subject16->GetTwoByteData(),
-                             offsets.vector(), offsets.length());
+      matches = JscreExecOnce(regexp,
+                              num_captures,
+                              subject,
+                              previous_index,
+                              subject16->GetTwoByteData(),
+                              offsets.vector(),
+                              offsets.length());
 
       if (matches->IsJSArray()) {
         SetElement(result, i, matches);
@@ -562,15 +802,1798 @@ Handle<Object> RegExpImpl::JsreExecGlobal(Handle<JSRegExp> regexp,
 }
 
 
-int RegExpImpl::JsreCapture(Handle<JSRegExp> re) {
+int RegExpImpl::JscreNumberOfCaptures(Handle<JSRegExp> re) {
   FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex));
-  return Smi::cast(value->get(CAPTURE_INDEX))->value();
+  return Smi::cast(value->get(kJscreNumberOfCapturesIndex))->
+      value();
 }
 
 
-ByteArray* RegExpImpl::JsreInternal(Handle<JSRegExp> re) {
+ByteArray* RegExpImpl::JscreInternal(Handle<JSRegExp> re) {
   FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex));
-  return ByteArray::cast(value->get(INTERNAL_INDEX));
+  return ByteArray::cast(value->get(kJscreInternalIndex));
+}
+
+
+int RegExpImpl::IrregexpNumberOfCaptures(Handle<JSRegExp> re) {
+  FixedArray* value =
+      FixedArray::cast(re->DataAt(JSRegExp::kIrregexpDataIndex));
+  return Smi::cast(value->get(kIrregexpNumberOfCapturesIndex))->value();
+}
+
+
+int RegExpImpl::IrregexpNumberOfRegisters(Handle<JSRegExp> re) {
+  FixedArray* value =
+      FixedArray::cast(re->DataAt(JSRegExp::kIrregexpDataIndex));
+  return Smi::cast(value->get(kIrregexpNumberOfRegistersIndex))->value();
+}
+
+
+Handle<ByteArray> RegExpImpl::IrregexpCode(Handle<JSRegExp> re) {
+  FixedArray* value =
+      FixedArray::cast(re->DataAt(JSRegExp::kIrregexpDataIndex));
+  return Handle<ByteArray>(ByteArray::cast(value->get(kIrregexpCodeIndex)));
+}
+
+
+// -------------------------------------------------------------------
+// New regular expression engine
+
+
+void RegExpTree::AppendToText(RegExpText* text) {
+  UNREACHABLE();
+}
+
+
+void RegExpAtom::AppendToText(RegExpText* text) {
+  text->AddElement(TextElement::Atom(this));
+}
+
+
+void RegExpCharacterClass::AppendToText(RegExpText* text) {
+  text->AddElement(TextElement::CharClass(this));
+}
+
+
+void RegExpText::AppendToText(RegExpText* text) {
+  for (int i = 0; i < elements()->length(); i++)
+    text->AddElement(elements()->at(i));
+}
+
+
+TextElement TextElement::Atom(RegExpAtom* atom) {
+  TextElement result = TextElement(ATOM);
+  result.data.u_atom = atom;
+  return result;
+}
+
+
+TextElement TextElement::CharClass(
+      RegExpCharacterClass* char_class) {
+  TextElement result = TextElement(CHAR_CLASS);
+  result.data.u_char_class = char_class;
+  return result;
+}
+
+
+class RegExpCompiler {
+ public:
+  RegExpCompiler(int capture_count, bool ignore_case);
+
+  int AllocateRegister() { return next_register_++; }
+
+  Handle<FixedArray> Assemble(RegExpMacroAssembler* assembler,
+                              RegExpNode* start,
+                              int capture_count);
+
+  inline void AddWork(RegExpNode* node) { work_list_->Add(node); }
+
+  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_; }
+  EndNode* backtrack() { return backtrack_; }
+
+  static const int kMaxRecursion = 100;
+  inline int recursion_depth() { return recursion_depth_; }
+  inline void IncrementRecursionDepth() { recursion_depth_++; }
+  inline void DecrementRecursionDepth() { recursion_depth_--; }
+
+  inline bool is_case_independent() { return is_case_independent_; }
+
+ private:
+  EndNode* accept_;
+  EndNode* backtrack_;
+  int next_register_;
+  List<RegExpNode*>* work_list_;
+  int recursion_depth_;
+  RegExpMacroAssembler* macro_assembler_;
+  bool is_case_independent_;
+};
+
+
+// Attempts to compile the regexp using an Irregexp code generator.  Returns
+// a fixed array or a null handle depending on whether it succeeded.
+RegExpCompiler::RegExpCompiler(int capture_count, bool ignore_case)
+  : next_register_(2 * (capture_count + 1)),
+    work_list_(NULL),
+    recursion_depth_(0),
+    is_case_independent_(ignore_case) {
+  accept_ = new EndNode(EndNode::ACCEPT);
+  backtrack_ = new EndNode(EndNode::BACKTRACK);
+}
+
+
+Handle<FixedArray> RegExpCompiler::Assemble(
+    RegExpMacroAssembler* macro_assembler,
+    RegExpNode* start,
+    int capture_count) {
+  if (!FLAG_attempt_case_independent && is_case_independent_) {
+    return Handle<FixedArray>::null();
+  }
+  macro_assembler_ = macro_assembler;
+  List <RegExpNode*> work_list(0);
+  work_list_ = &work_list;
+  Label fail;
+  macro_assembler->PushBacktrack(&fail);
+  if (!start->GoTo(this)) {
+    fail.Unuse();
+    return Handle<FixedArray>::null();
+  }
+  while (!work_list.is_empty()) {
+    if (!work_list.RemoveLast()->GoTo(this)) {
+      fail.Unuse();
+      return Handle<FixedArray>::null();
+    }
+  }
+  macro_assembler->Bind(&fail);
+  macro_assembler->Fail();
+  Handle<FixedArray> array =
+      Factory::NewFixedArray(RegExpImpl::kIrregexpDataLength);
+  array->set(RegExpImpl::kIrregexpImplementationIndex,
+             Smi::FromInt(macro_assembler->Implementation()));
+  array->set(RegExpImpl::kIrregexpNumberOfRegistersIndex,
+             Smi::FromInt(next_register_));
+  array->set(RegExpImpl::kIrregexpNumberOfCapturesIndex,
+             Smi::FromInt(capture_count));
+  Handle<Object> code = macro_assembler->GetCode();
+  array->set(RegExpImpl::kIrregexpCodeIndex, *code);
+  work_list_ = NULL;
+  return array;
+}
+
+
+bool RegExpNode::GoTo(RegExpCompiler* compiler) {
+  // TODO(erikcorry): Implement support.
+  if (info_.follows_word_interest ||
+      info_.follows_newline_interest ||
+      info_.follows_start_interest) {
+    return false;
+  }
+  if (label_.is_bound()) {
+    compiler->macro_assembler()->GoTo(&label_);
+    return true;
+  } else {
+    if (compiler->recursion_depth() > RegExpCompiler::kMaxRecursion) {
+      compiler->macro_assembler()->GoTo(&label_);
+      compiler->AddWork(this);
+      return true;
+    } else {
+      compiler->IncrementRecursionDepth();
+      bool how_it_went = Emit(compiler);
+      compiler->DecrementRecursionDepth();
+      return how_it_went;
+    }
+  }
+}
+
+
+bool EndNode::GoTo(RegExpCompiler* compiler) {
+  if (info()->follows_word_interest ||
+      info()->follows_newline_interest ||
+      info()->follows_start_interest) {
+    return false;
+  }
+  if (!label()->is_bound()) {
+    Bind(compiler->macro_assembler());
+  }
+  switch (action_) {
+    case ACCEPT:
+      compiler->macro_assembler()->Succeed();
+    break;
+    case BACKTRACK:
+      compiler->macro_assembler()->Backtrack();
+    break;
+  }
+  return true;
+}
+
+
+Label* RegExpNode::label() {
+  return &label_;
+}
+
+
+bool EndNode::Emit(RegExpCompiler* compiler) {
+  RegExpMacroAssembler* macro = compiler->macro_assembler();
+  switch (action_) {
+    case ACCEPT:
+      Bind(macro);
+      macro->Succeed();
+      return true;
+    case BACKTRACK:
+      Bind(macro);
+      macro->Backtrack();
+      return true;
+  }
+  return false;
+}
+
+
+void GuardedAlternative::AddGuard(Guard* guard) {
+  if (guards_ == NULL)
+    guards_ = new ZoneList<Guard*>(1);
+  guards_->Add(guard);
+}
+
+
+ActionNode* ActionNode::StoreRegister(int reg,
+                                      int val,
+                                      RegExpNode* on_success) {
+  ActionNode* result = new ActionNode(STORE_REGISTER, on_success);
+  result->data_.u_store_register.reg = reg;
+  result->data_.u_store_register.value = val;
+  return result;
+}
+
+
+ActionNode* ActionNode::IncrementRegister(int reg, RegExpNode* on_success) {
+  ActionNode* result = new ActionNode(INCREMENT_REGISTER, on_success);
+  result->data_.u_increment_register.reg = reg;
+  return result;
 }
 
+
+ActionNode* ActionNode::StorePosition(int reg, RegExpNode* on_success) {
+  ActionNode* result = new ActionNode(STORE_POSITION, on_success);
+  result->data_.u_position_register.reg = reg;
+  return result;
+}
+
+
+ActionNode* ActionNode::SavePosition(int reg, RegExpNode* on_success) {
+  ActionNode* result = new ActionNode(SAVE_POSITION, on_success);
+  result->data_.u_position_register.reg = reg;
+  return result;
+}
+
+
+ActionNode* ActionNode::RestorePosition(int reg, RegExpNode* on_success) {
+  ActionNode* result = new ActionNode(RESTORE_POSITION, on_success);
+  result->data_.u_position_register.reg = reg;
+  return result;
+}
+
+
+ActionNode* ActionNode::BeginSubmatch(int reg, RegExpNode* on_success) {
+  ActionNode* result = new ActionNode(BEGIN_SUBMATCH, on_success);
+  result->data_.u_submatch_stack_pointer_register.reg = reg;
+  return result;
+}
+
+
+ActionNode* ActionNode::EscapeSubmatch(int reg, RegExpNode* on_success) {
+  ActionNode* result = new ActionNode(ESCAPE_SUBMATCH, on_success);
+  result->data_.u_submatch_stack_pointer_register.reg = reg;
+  return result;
+}
+
+
+#define DEFINE_ACCEPT(Type)                                          \
+  void Type##Node::Accept(NodeVisitor* visitor) {                    \
+    visitor->Visit##Type(this);                                      \
+  }
+FOR_EACH_NODE_TYPE(DEFINE_ACCEPT)
+#undef DEFINE_ACCEPT
+
+
+// -------------------------------------------------------------------
+// Emit code.
+
+
+void ChoiceNode::GenerateGuard(RegExpMacroAssembler* macro_assembler,
+                               Guard* guard,
+                               Label* on_failure) {
+  switch (guard->op()) {
+    case Guard::LT:
+      macro_assembler->IfRegisterGE(guard->reg(), guard->value(), on_failure);
+      break;
+    case Guard::GEQ:
+      macro_assembler->IfRegisterLT(guard->reg(), guard->value(), on_failure);
+      break;
+  }
+}
+
+
+static unibrow::Mapping<unibrow::Ecma262UnCanonicalize> uncanonicalize;
+static unibrow::Mapping<unibrow::CanonicalizationRange> canonrange;
+
+
+static inline void EmitAtomNonLetters(
+    RegExpMacroAssembler* macro_assembler,
+    TextElement elm,
+    Vector<const uc16> quarks,
+    Label* on_failure,
+    int cp_offset) {
+  unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+  for (int i = quarks.length() - 1; i >= 0; i--) {
+    uc16 c = quarks[i];
+    int length = uncanonicalize.get(c, '\0', chars);
+    if (length <= 1) {
+      macro_assembler->LoadCurrentCharacter(cp_offset + i, on_failure);
+      macro_assembler->CheckNotCharacter(c, on_failure);
+    }
+  }
+}
+
+
+static bool ShortCutEmitCharacterPair(RegExpMacroAssembler* macro_assembler,
+                                      uc16 c1,
+                                      uc16 c2,
+                                      Label* on_failure) {
+  uc16 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.
+    // Ecma262UnCanonicalize always gives the highest number last.
+    ASSERT(c2 > c1);
+    macro_assembler->CheckNotCharacterAfterOr(c2, exor, on_failure);
+    return true;
+  } else {
+    ASSERT(c2 > c1);
+    uc16 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.
+      macro_assembler->CheckNotCharacterAfterMinusOr(c2 - diff,
+                                                     diff,
+                                                     on_failure);
+      return true;
+    }
+  }
+  return false;
+}
+
+
+static inline void EmitAtomLetters(
+    RegExpMacroAssembler* macro_assembler,
+    TextElement elm,
+    Vector<const uc16> quarks,
+    Label* on_failure,
+    int cp_offset) {
+  unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+  for (int i = quarks.length() - 1; i >= 0; i--) {
+    uc16 c = quarks[i];
+    int length = uncanonicalize.get(c, '\0', chars);
+    if (length <= 1) continue;
+    macro_assembler->LoadCurrentCharacter(cp_offset + i, on_failure);
+    Label ok;
+    ASSERT(unibrow::Ecma262UnCanonicalize::kMaxWidth == 4);
+    switch (length) {
+      case 2: {
+        if (ShortCutEmitCharacterPair(macro_assembler,
+                                      chars[0],
+                                      chars[1],
+                                      on_failure)) {
+          ok.Unuse();
+        } 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:
+        UNREACHABLE();
+        break;
+    }
+  }
+}
+
+
+static void EmitCharClass(RegExpMacroAssembler* macro_assembler,
+                          RegExpCharacterClass* cc,
+                          int cp_offset,
+                          Label* on_failure) {
+  macro_assembler->LoadCurrentCharacter(cp_offset, on_failure);
+  cp_offset++;
+
+  ZoneList<CharacterRange>* ranges = cc->ranges();
+
+  Label success;
+
+  Label *char_is_in_class =
+      cc->is_negated() ? on_failure : &success;
+
+  int range_count = ranges->length();
+
+  if (range_count == 0) {
+    if (!cc->is_negated()) {
+      macro_assembler->GoTo(on_failure);
+    }
+    return;
+  }
+
+  for (int i = 0; i < range_count - 1; i++) {
+    CharacterRange& range = ranges->at(i);
+    Label next_range;
+    uc16 from = range.from();
+    uc16 to = range.to();
+    if (to == from) {
+      macro_assembler->CheckCharacter(to, char_is_in_class);
+    } else {
+      if (from != 0) {
+        macro_assembler->CheckCharacterLT(from, &next_range);
+      }
+      if (to != 0xffff) {
+        macro_assembler->CheckCharacterLT(to + 1, char_is_in_class);
+      } else {
+        macro_assembler->GoTo(char_is_in_class);
+      }
+    }
+    macro_assembler->Bind(&next_range);
+  }
+
+  CharacterRange& range = ranges->at(range_count - 1);
+  uc16 from = range.from();
+  uc16 to = range.to();
+
+  if (to == from) {
+    if (cc->is_negated()) {
+      macro_assembler->CheckCharacter(to, on_failure);
+    } else {
+      macro_assembler->CheckNotCharacter(to, on_failure);
+    }
+  } else {
+    if (from != 0) {
+      if (!cc->is_negated()) {
+        macro_assembler->CheckCharacterLT(from, on_failure);
+      } else {
+        macro_assembler->CheckCharacterLT(from, &success);
+      }
+    }
+    if (to != 0xffff) {
+      if (!cc->is_negated()) {
+        macro_assembler->CheckCharacterGT(to, on_failure);
+      } else {
+        macro_assembler->CheckCharacterLT(to + 1, on_failure);
+      }
+    } else {
+      if (cc->is_negated()) {
+        macro_assembler->GoTo(on_failure);
+      }
+    }
+  }
+  macro_assembler->Bind(&success);
+}
+
+
+
+bool TextNode::Emit(RegExpCompiler* compiler) {
+  RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
+  Bind(macro_assembler);
+  int element_count = elms_->length();
+  int cp_offset = 0;
+  // First, handle straight character matches.
+  for (int i = 0; i < element_count; i++) {
+    TextElement elm = elms_->at(i);
+    if (elm.type == TextElement::ATOM) {
+      Vector<const uc16> quarks = elm.data.u_atom->data();
+      if (!compiler->is_case_independent()) {
+        macro_assembler->CheckCharacters(quarks,
+                                         cp_offset,
+                                         on_failure_->label());
+      } else {
+        EmitAtomNonLetters(macro_assembler,
+                           elm,
+                           quarks,
+                           on_failure_->label(),
+                           cp_offset);
+      }
+      cp_offset += quarks.length();
+    } else {
+      ASSERT_EQ(elm.type, TextElement::CHAR_CLASS);
+      cp_offset++;
+    }
+  }
+  // Second, handle case independent letter matches if any.
+  if (compiler->is_case_independent()) {
+    cp_offset = 0;
+    for (int i = 0; i < element_count; i++) {
+      TextElement elm = elms_->at(i);
+      if (elm.type == TextElement::ATOM) {
+        Vector<const uc16> quarks = elm.data.u_atom->data();
+        EmitAtomLetters(macro_assembler,
+                        elm,
+                        quarks,
+                        on_failure_->label(),
+                        cp_offset);
+        cp_offset += quarks.length();
+      } else {
+        cp_offset++;
+      }
+    }
+  }
+  // If the fast character matches passed then do the character classes.
+  cp_offset = 0;
+  for (int i = 0; i < element_count; i++) {
+    TextElement elm = elms_->at(i);
+    if (elm.type == TextElement::CHAR_CLASS) {
+      RegExpCharacterClass* cc = elm.data.u_char_class;
+      EmitCharClass(macro_assembler, cc, cp_offset, on_failure_->label());
+      cp_offset++;
+    } else {
+      cp_offset += elm.data.u_atom->data().length();
+    }
+  }
+
+  compiler->AddWork(on_failure_);
+  macro_assembler->AdvanceCurrentPosition(cp_offset);
+  return on_success()->GoTo(compiler);
+}
+
+
+bool ChoiceNode::Emit(RegExpCompiler* compiler) {
+  int choice_count = alternatives_->length();
+  RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
+  Bind(macro_assembler);
+  // 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.
+  int i;
+  for (i = 0; i < choice_count - 1; i++) {
+    GuardedAlternative alternative = alternatives_->at(i);
+    Label after;
+    Label after_no_pop_cp;
+    ZoneList<Guard*>* guards = alternative.guards();
+    if (guards != NULL) {
+      int guard_count = guards->length();
+      for (int j = 0; j < guard_count; j++) {
+        GenerateGuard(macro_assembler, guards->at(j), &after_no_pop_cp);
+      }
+    }
+    macro_assembler->PushCurrentPosition();
+    macro_assembler->PushBacktrack(&after);
+    if (!alternative.node()->GoTo(compiler)) {
+      after.Unuse();
+      after_no_pop_cp.Unuse();
+      return false;
+    }
+    macro_assembler->Bind(&after);
+    macro_assembler->PopCurrentPosition();
+    macro_assembler->Bind(&after_no_pop_cp);
+  }
+  GuardedAlternative alternative = alternatives_->at(i);
+  ZoneList<Guard*>* guards = alternative.guards();
+  if (guards != NULL) {
+    int guard_count = guards->length();
+    for (int j = 0; j < guard_count; j++) {
+      GenerateGuard(macro_assembler, guards->at(j), on_failure_->label());
+    }
+  }
+  if (!on_failure_->IsBacktrack()) {
+    ASSERT_NOT_NULL(on_failure_ -> label());
+    macro_assembler->PushBacktrack(on_failure_->label());
+    compiler->AddWork(on_failure_);
+  }
+  if (!alternative.node()->GoTo(compiler)) {
+    return false;
+  }
+  return true;
+}
+
+
+bool ActionNode::Emit(RegExpCompiler* compiler) {
+  RegExpMacroAssembler* macro = compiler->macro_assembler();
+  Bind(macro);
+  switch (type_) {
+    case STORE_REGISTER:
+      macro->SetRegister(data_.u_store_register.reg,
+                         data_.u_store_register.value);
+      break;
+    case INCREMENT_REGISTER: {
+      Label undo;
+      macro->PushBacktrack(&undo);
+      macro->AdvanceRegister(data_.u_increment_register.reg, 1);
+      bool ok = on_success()->GoTo(compiler);
+      if (!ok) {
+        undo.Unuse();
+        return false;
+      }
+      macro->Bind(&undo);
+      macro->AdvanceRegister(data_.u_increment_register.reg, -1);
+      macro->Backtrack();
+      break;
+    }
+    case STORE_POSITION: {
+      Label undo;
+      macro->PushRegister(data_.u_position_register.reg);
+      macro->PushBacktrack(&undo);
+      macro->WriteCurrentPositionToRegister(data_.u_position_register.reg);
+      bool ok = on_success()->GoTo(compiler);
+      if (!ok) {
+        undo.Unuse();
+        return false;
+      }
+      macro->Bind(&undo);
+      macro->PopRegister(data_.u_position_register.reg);
+      macro->Backtrack();
+      break;
+    }
+    case SAVE_POSITION:
+      macro->WriteCurrentPositionToRegister(
+          data_.u_position_register.reg);
+      break;
+    case RESTORE_POSITION:
+      macro->ReadCurrentPositionFromRegister(
+          data_.u_position_register.reg);
+      break;
+    case BEGIN_SUBMATCH:
+      macro->WriteStackPointerToRegister(
+          data_.u_submatch_stack_pointer_register.reg);
+      break;
+    case ESCAPE_SUBMATCH:
+      macro->ReadStackPointerFromRegister(
+          data_.u_submatch_stack_pointer_register.reg);
+      break;
+    default:
+      UNREACHABLE();
+      return false;
+  }
+  return on_success()->GoTo(compiler);
+}
+
+
+bool BackReferenceNode::Emit(RegExpCompiler* compiler) {
+  RegExpMacroAssembler* macro = compiler->macro_assembler();
+  Bind(macro);
+  // Check whether the registers are uninitialized and always
+  // succeed if they are.
+  macro->IfRegisterLT(start_reg_, 0, on_success()->label());
+  macro->IfRegisterLT(end_reg_, 0, on_success()->label());
+  ASSERT_EQ(start_reg_ + 1, end_reg_);
+  macro->CheckNotBackReference(start_reg_, on_failure_->label());
+  return on_success()->GoTo(compiler);
+}
+
+
+// -------------------------------------------------------------------
+// Dot/dotty output
+
+
+#ifdef DEBUG
+
+
+class DotPrinter: public NodeVisitor {
+ public:
+  DotPrinter() : stream_(&alloc_) { }
+  void PrintNode(const char* label, RegExpNode* node);
+  void Visit(RegExpNode* node);
+  void PrintOnFailure(RegExpNode* from, RegExpNode* on_failure);
+  StringStream* stream() { return &stream_; }
+#define DECLARE_VISIT(Type)                                          \
+  virtual void Visit##Type(Type##Node* that);
+FOR_EACH_NODE_TYPE(DECLARE_VISIT)
+#undef DECLARE_VISIT
+ private:
+  HeapStringAllocator alloc_;
+  StringStream stream_;
+  std::set<RegExpNode*> seen_;
+};
+
+
+void DotPrinter::PrintNode(const char* label, RegExpNode* node) {
+  stream()->Add("digraph G {\n  graph [label=\"");
+  for (int i = 0; label[i]; i++) {
+    switch (label[i]) {
+      case '\\':
+        stream()->Add("\\\\");
+        break;
+      case '"':
+        stream()->Add("\"");
+        break;
+      default:
+        stream()->Put(label[i]);
+        break;
+    }
+  }
+  stream()->Add("\"];\n");
+  Visit(node);
+  stream()->Add("}\n");
+  printf("%s", *(stream()->ToCString()));
+}
+
+
+void DotPrinter::Visit(RegExpNode* node) {
+  if (seen_.find(node) != seen_.end())
+    return;
+  seen_.insert(node);
+  node->Accept(this);
+}
+
+
+void DotPrinter::PrintOnFailure(RegExpNode* from, RegExpNode* on_failure) {
+  if (on_failure->IsBacktrack()) return;
+  stream()->Add("  n%p -> n%p [style=dotted];\n", from, on_failure);
+  Visit(on_failure);
+}
+
+
+class TableEntryBodyPrinter {
+ public:
+  TableEntryBodyPrinter(StringStream* stream, ChoiceNode* choice)
+    : stream_(stream), choice_(choice) { }
+  void Call(uc16 from, DispatchTable::Entry entry) {
+    OutSet* out_set = entry.out_set();
+    for (unsigned i = 0; i < OutSet::kFirstLimit; i++) {
+      if (out_set->Get(i)) {
+        stream()->Add("    n%p:s%io%i -> n%p;\n",
+                      choice(),
+                      from,
+                      i,
+                      choice()->alternatives()->at(i).node());
+      }
+    }
+  }
+ private:
+  StringStream* stream() { return stream_; }
+  ChoiceNode* choice() { return choice_; }
+  StringStream* stream_;
+  ChoiceNode* choice_;
+};
+
+
+class TableEntryHeaderPrinter {
+ public:
+  explicit TableEntryHeaderPrinter(StringStream* stream)
+    : first_(true), stream_(stream) { }
+  void Call(uc16 from, DispatchTable::Entry entry) {
+    if (first_) {
+      first_ = false;
+    } else {
+      stream()->Add("|");
+    }
+    stream()->Add("{\\%k-\\%k|{", from, entry.to());
+    OutSet* out_set = entry.out_set();
+    int priority = 0;
+    for (unsigned i = 0; i < OutSet::kFirstLimit; i++) {
+      if (out_set->Get(i)) {
+        if (priority > 0) stream()->Add("|");
+        stream()->Add("<s%io%i> %i", from, i, priority);
+        priority++;
+      }
+    }
+    stream()->Add("}}");
+  }
+ private:
+  bool first_;
+  StringStream* stream() { return stream_; }
+  StringStream* stream_;
+};
+
+
+void DotPrinter::VisitChoice(ChoiceNode* that) {
+  stream()->Add("  n%p [shape=Mrecord, label=\"", that);
+  TableEntryHeaderPrinter header_printer(stream());
+  that->table()->ForEach(&header_printer);
+  stream()->Add("\"]\n", that);
+  TableEntryBodyPrinter body_printer(stream(), that);
+  that->table()->ForEach(&body_printer);
+  PrintOnFailure(that, that->on_failure());
+  for (int i = 0; i < that->alternatives()->length(); i++) {
+    GuardedAlternative alt = that->alternatives()->at(i);
+    alt.node()->Accept(this);
+  }
+}
+
+
+void DotPrinter::VisitText(TextNode* that) {
+  stream()->Add("  n%p [label=\"", that);
+  for (int i = 0; i < that->elements()->length(); i++) {
+    if (i > 0) stream()->Add(" ");
+    TextElement elm = that->elements()->at(i);
+    switch (elm.type) {
+      case TextElement::ATOM: {
+        stream()->Add("'%w'", elm.data.u_atom->data());
+        break;
+      }
+      case TextElement::CHAR_CLASS: {
+        RegExpCharacterClass* node = elm.data.u_char_class;
+        stream()->Add("[");
+        if (node->is_negated())
+          stream()->Add("^");
+        for (int j = 0; j < node->ranges()->length(); j++) {
+          CharacterRange range = node->ranges()->at(j);
+          stream()->Add("%k-%k", range.from(), range.to());
+        }
+        stream()->Add("]");
+        break;
+      }
+      default:
+        UNREACHABLE();
+    }
+  }
+  stream()->Add("\", shape=box, peripheries=2];\n");
+  stream()->Add("  n%p -> n%p;\n", that, that->on_success());
+  Visit(that->on_success());
+  PrintOnFailure(that, that->on_failure());
+}
+
+
+void DotPrinter::VisitBackReference(BackReferenceNode* that) {
+  stream()->Add("  n%p [label=\"$%i..$%i\", shape=doubleoctagon];\n",
+                that,
+                that->start_register(),
+                that->end_register());
+  stream()->Add("  n%p -> n%p;\n", that, that->on_success());
+  Visit(that->on_success());
+  PrintOnFailure(that, that->on_failure());
+}
+
+
+void DotPrinter::VisitEnd(EndNode* that) {
+  stream()->Add("  n%p [style=bold, shape=point];\n", that);
+}
+
+
+void DotPrinter::VisitAction(ActionNode* that) {
+  stream()->Add("  n%p [", that);
+  switch (that->type_) {
+    case ActionNode::STORE_REGISTER:
+      stream()->Add("label=\"$%i:=%i\", shape=octagon",
+                    that->data_.u_store_register.reg,
+                    that->data_.u_store_register.value);
+      break;
+    case ActionNode::INCREMENT_REGISTER:
+      stream()->Add("label=\"$%i++\", shape=octagon",
+                    that->data_.u_increment_register.reg);
+      break;
+    case ActionNode::STORE_POSITION:
+      stream()->Add("label=\"$%i:=$pos\", shape=octagon",
+                    that->data_.u_position_register.reg);
+      break;
+    case ActionNode::SAVE_POSITION:
+      stream()->Add("label=\"$%i:=$pos\", shape=octagon",
+                    that->data_.u_position_register.reg);
+      break;
+    case ActionNode::RESTORE_POSITION:
+      stream()->Add("label=\"$pos:=$%i\", shape=octagon",
+                    that->data_.u_position_register.reg);
+      break;
+    case ActionNode::BEGIN_SUBMATCH:
+      stream()->Add("label=\"begin\", shape=septagon");
+      break;
+    case ActionNode::ESCAPE_SUBMATCH:
+      stream()->Add("label=\"escape\", shape=septagon");
+      break;
+  }
+  stream()->Add("];\n");
+  stream()->Add("  n%p -> n%p;\n", that, that->on_success());
+  Visit(that->on_success());
+}
+
+
+class DispatchTableDumper {
+ public:
+  explicit DispatchTableDumper(StringStream* stream) : stream_(stream) { }
+  void Call(uc16 key, DispatchTable::Entry entry);
+  StringStream* stream() { return stream_; }
+ private:
+  StringStream* stream_;
+};
+
+
+void DispatchTableDumper::Call(uc16 key, DispatchTable::Entry entry) {
+  stream()->Add("[%k-%k]: {", key, entry.to());
+  OutSet* set = entry.out_set();
+  bool first = true;
+  for (unsigned i = 0; i < OutSet::kFirstLimit; i++) {
+    if (set->Get(i)) {
+      if (first) {
+        first = false;
+      } else {
+        stream()->Add(", ");
+      }
+      stream()->Add("%i", i);
+    }
+  }
+  stream()->Add("}\n");
+}
+
+
+void DispatchTable::Dump() {
+  HeapStringAllocator alloc;
+  StringStream stream(&alloc);
+  DispatchTableDumper dumper(&stream);
+  tree()->ForEach(&dumper);
+  OS::PrintError("%s", *stream.ToCString());
+}
+
+
+void RegExpEngine::DotPrint(const char* label, RegExpNode* node) {
+  DotPrinter printer;
+  printer.PrintNode(label, node);
+}
+
+
+#endif  // DEBUG
+
+
+// -------------------------------------------------------------------
+// Tree to graph conversion
+
+
+RegExpNode* RegExpAtom::ToNode(RegExpCompiler* compiler,
+                               RegExpNode* on_success,
+                               RegExpNode* on_failure) {
+  ZoneList<TextElement>* elms = new ZoneList<TextElement>(1);
+  elms->Add(TextElement::Atom(this));
+  return new TextNode(elms, on_success, on_failure);
+}
+
+
+RegExpNode* RegExpText::ToNode(RegExpCompiler* compiler,
+                               RegExpNode* on_success,
+                               RegExpNode* on_failure) {
+  return new TextNode(elements(), on_success, on_failure);
+}
+
+
+RegExpNode* RegExpCharacterClass::ToNode(RegExpCompiler* compiler,
+                                         RegExpNode* on_success,
+                                         RegExpNode* on_failure) {
+  ZoneList<TextElement>* elms = new ZoneList<TextElement>(1);
+  elms->Add(TextElement::CharClass(this));
+  return new TextNode(elms, on_success, on_failure);
+}
+
+
+RegExpNode* RegExpDisjunction::ToNode(RegExpCompiler* compiler,
+                                      RegExpNode* on_success,
+                                      RegExpNode* on_failure) {
+  ZoneList<RegExpTree*>* alternatives = this->alternatives();
+  int length = alternatives->length();
+  ChoiceNode* result = new ChoiceNode(length, on_failure);
+  for (int i = 0; i < length; i++) {
+    GuardedAlternative alternative(alternatives->at(i)->ToNode(compiler,
+                                                               on_success,
+                                                               on_failure));
+    result->AddAlternative(alternative);
+  }
+  return result;
+}
+
+
+RegExpNode* RegExpQuantifier::ToNode(RegExpCompiler* compiler,
+                                     RegExpNode* on_success,
+                                     RegExpNode* on_failure) {
+  return ToNode(min(),
+                max(),
+                is_greedy(),
+                body(),
+                compiler,
+                on_success,
+                on_failure);
+}
+
+
+RegExpNode* RegExpQuantifier::ToNode(int min,
+                                     int max,
+                                     bool is_greedy,
+                                     RegExpTree* body,
+                                     RegExpCompiler* compiler,
+                                     RegExpNode* on_success,
+                                     RegExpNode* on_failure) {
+  // x{f, t} becomes this:
+  //
+  //             (r++)<-.
+  //               |     `
+  //               |     (x)
+  //               v     ^
+  //      (r=0)-->(?)---/ [if r < t]
+  //               |
+  //   [if r >= f] \----> ...
+  //
+  //
+  // TODO(someone): clear captures on repetition and handle empty
+  //   matches.
+  bool has_min = min > 0;
+  bool has_max = max < RegExpQuantifier::kInfinity;
+  bool needs_counter = has_min || has_max;
+  int reg_ctr = needs_counter ? compiler->AllocateRegister() : -1;
+  ChoiceNode* center = new ChoiceNode(2, on_failure);
+  RegExpNode* loop_return = needs_counter
+      ? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center))
+      : static_cast<RegExpNode*>(center);
+  RegExpNode* body_node = body->ToNode(compiler, loop_return, on_failure);
+  GuardedAlternative body_alt(body_node);
+  if (has_max) {
+    Guard* body_guard = new Guard(reg_ctr, Guard::LT, max);
+    body_alt.AddGuard(body_guard);
+  }
+  GuardedAlternative rest_alt(on_success);
+  if (has_min) {
+    Guard* rest_guard = new Guard(reg_ctr, Guard::GEQ, min);
+    rest_alt.AddGuard(rest_guard);
+  }
+  if (is_greedy) {
+    center->AddAlternative(body_alt);
+    center->AddAlternative(rest_alt);
+  } else {
+    center->AddAlternative(rest_alt);
+    center->AddAlternative(body_alt);
+  }
+  if (needs_counter) {
+    return ActionNode::StoreRegister(reg_ctr, 0, center);
+  } else {
+    return center;
+  }
+}
+
+
+RegExpNode* RegExpAssertion::ToNode(RegExpCompiler* compiler,
+                                    RegExpNode* on_success,
+                                    RegExpNode* on_failure) {
+  NodeInfo info;
+  switch (type()) {
+    case START_OF_LINE:
+      info.follows_newline_interest = true;
+      break;
+    case START_OF_INPUT:
+      info.follows_start_interest = true;
+      break;
+    case BOUNDARY: case NON_BOUNDARY:
+      info.follows_word_interest = true;
+      break;
+    case END_OF_LINE: case END_OF_INPUT:
+      // This is wrong but has the effect of making the compiler abort.
+      info.follows_start_interest = true;
+  }
+  return on_success->PropagateInterest(&info);
+}
+
+
+RegExpNode* RegExpBackReference::ToNode(RegExpCompiler* compiler,
+                                        RegExpNode* on_success,
+                                        RegExpNode* on_failure) {
+  return new BackReferenceNode(RegExpCapture::StartRegister(index()),
+                               RegExpCapture::EndRegister(index()),
+                               on_success,
+                               on_failure);
+}
+
+
+RegExpNode* RegExpEmpty::ToNode(RegExpCompiler* compiler,
+                                RegExpNode* on_success,
+                                RegExpNode* on_failure) {
+  return on_success;
+}
+
+
+RegExpNode* RegExpLookahead::ToNode(RegExpCompiler* compiler,
+                                    RegExpNode* on_success,
+                                    RegExpNode* on_failure) {
+  int stack_pointer_register = compiler->AllocateRegister();
+  int position_register = compiler->AllocateRegister();
+  if (is_positive()) {
+    // begin submatch scope
+    // $reg = $pos
+    // if [body]
+    // then
+    //   $pos = $reg
+    //   escape submatch scope (drop all backtracks created in scope)
+    //   succeed
+    // else
+    //   end submatch scope (nothing to clean up, just exit the scope)
+    //   fail
+    return ActionNode::BeginSubmatch(
+        stack_pointer_register,
+        ActionNode::SavePosition(
+            position_register,
+            body()->ToNode(
+                compiler,
+                ActionNode::RestorePosition(
+                    position_register,
+                    ActionNode::EscapeSubmatch(stack_pointer_register,
+                                               on_success)),
+                on_failure)));
+  } else {
+    // begin submatch scope
+    // try
+    // first if (body)
+    //       then
+    //         escape submatch scope
+    //         fail
+    //       else
+    //         backtrack
+    // second
+    //       end submatch scope
+    //       restore current position
+    //       succeed
+    ChoiceNode* try_node =
+        new ChoiceNode(1, ActionNode::RestorePosition(position_register,
+                                                      on_success));
+    RegExpNode* body_node = body()->ToNode(
+        compiler,
+        ActionNode::EscapeSubmatch(stack_pointer_register, on_failure),
+        compiler->backtrack());
+    GuardedAlternative body_alt(body_node);
+    try_node->AddAlternative(body_alt);
+    return ActionNode::BeginSubmatch(stack_pointer_register,
+                                     ActionNode::SavePosition(
+                                         position_register,
+                                         try_node));
+  }
+}
+
+
+RegExpNode* RegExpCapture::ToNode(RegExpCompiler* compiler,
+                                  RegExpNode* on_success,
+                                  RegExpNode* on_failure) {
+  return ToNode(body(), index(), compiler, on_success, on_failure);
+}
+
+
+RegExpNode* RegExpCapture::ToNode(RegExpTree* body,
+                                  int index,
+                                  RegExpCompiler* compiler,
+                                  RegExpNode* on_success,
+                                  RegExpNode* on_failure) {
+  int start_reg = RegExpCapture::StartRegister(index);
+  int end_reg = RegExpCapture::EndRegister(index);
+  RegExpNode* store_end = ActionNode::StorePosition(end_reg, on_success);
+  RegExpNode* body_node = body->ToNode(compiler, store_end, on_failure);
+  return ActionNode::StorePosition(start_reg, body_node);
+}
+
+
+RegExpNode* RegExpAlternative::ToNode(RegExpCompiler* compiler,
+                                      RegExpNode* on_success,
+                                      RegExpNode* on_failure) {
+  ZoneList<RegExpTree*>* children = nodes();
+  RegExpNode* current = on_success;
+  for (int i = children->length() - 1; i >= 0; i--) {
+    current = children->at(i)->ToNode(compiler, current, on_failure);
+  }
+  return current;
+}
+
+
+static const int kSpaceRangeCount = 20;
+static const uc16 kSpaceRanges[kSpaceRangeCount] = {
+  0x0009, 0x000D, 0x0020, 0x0020, 0x00A0, 0x00A0, 0x1680,
+  0x1680, 0x180E, 0x180E, 0x2000, 0x200A, 0x2028, 0x2029,
+  0x202F, 0x202F, 0x205F, 0x205F, 0x3000, 0x3000
+};
+
+
+static const int kWordRangeCount = 8;
+static const uc16 kWordRanges[kWordRangeCount] = {
+  '0', '9', 'A', 'Z', '_', '_', 'a', 'z'
+};
+
+
+static const int kDigitRangeCount = 2;
+static const uc16 kDigitRanges[kDigitRangeCount] = {
+  '0', '9'
+};
+
+
+static const int kLineTerminatorRangeCount = 6;
+static const uc16 kLineTerminatorRanges[kLineTerminatorRangeCount] = {
+  0x000A, 0x000A, 0x000D, 0x000D, 0x2028, 0x2029
+};
+
+
+static void AddClass(const uc16* elmv,
+                     int elmc,
+                     ZoneList<CharacterRange>* ranges) {
+  for (int i = 0; i < elmc; i += 2) {
+    ASSERT(elmv[i] <= elmv[i + 1]);
+    ranges->Add(CharacterRange(elmv[i], elmv[i + 1]));
+  }
+}
+
+
+static void AddClassNegated(const uc16 *elmv,
+                            int elmc,
+                            ZoneList<CharacterRange>* ranges) {
+  ASSERT(elmv[0] != 0x0000);
+  ASSERT(elmv[elmc-1] != 0xFFFF);
+  uc16 last = 0x0000;
+  for (int i = 0; i < elmc; i += 2) {
+    ASSERT(last <= elmv[i] - 1);
+    ASSERT(elmv[i] <= elmv[i + 1]);
+    ranges->Add(CharacterRange(last, elmv[i] - 1));
+    last = elmv[i + 1] + 1;
+  }
+  ranges->Add(CharacterRange(last, 0xFFFF));
+}
+
+
+void CharacterRange::AddClassEscape(uc16 type,
+                                    ZoneList<CharacterRange>* 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->Add(CharacterRange::Everything());
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void CharacterRange::AddCaseEquivalents(ZoneList<CharacterRange>* ranges) {
+  unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+  if (IsSingleton()) {
+    // If this is a singleton we just expand the one character.
+    int length = uncanonicalize.get(from(), '\0', chars);
+    for (int i = 0; i < length; i++) {
+      uc32 chr = chars[i];
+      if (chr != from()) {
+        ranges->Add(CharacterRange::Singleton(chars[i]));
+      }
+    }
+  } else if (from() <= kRangeCanonicalizeMax
+          && to() <= kRangeCanonicalizeMax) {
+    // If this is a range we expand the characters block by block,
+    // expanding contiguous subranges (blocks) one at a time.
+    // The approach is as follows.  For a given start character we
+    // look up the block that contains it, for instance 'a' if the
+    // start character is 'c'.  A block is characterized by the property
+    // that all characters uncanonicalize in the same way as the first
+    // element, except that each entry in the result is incremented
+    // by the distance from the first element.  So a-z is a block
+    // because 'a' uncanonicalizes to ['a', 'A'] and the k'th letter
+    // uncanonicalizes to ['a' + k, 'A' + k].
+    // Once we've found the start point we look up its uncanonicalization
+    // and produce a range for each element.  For instance for [c-f]
+    // we look up ['a', 'A'] and produce [c-f] and [C-F].  We then only
+    // add a range if it is not already contained in the input, so [c-f]
+    // will be skipped but [C-F] will be added.  If this range is not
+    // completely contained in a block we do this for all the blocks
+    // covered by the range.
+    unibrow::uchar range[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+    // First, look up the block that contains the 'from' character.
+    int length = canonrange.get(from(), '\0', range);
+    if (length == 0) {
+      range[0] = from();
+    } else {
+      ASSERT_EQ(1, length);
+    }
+    int pos = from();
+    // The start of the current block.  Note that except for the first
+    // iteration 'start' is always equal to 'pos'.
+    int start;
+    // If it is not the start point of a block the entry contains the
+    // offset of the character from the start point.
+    if ((range[0] & kStartMarker) == 0) {
+      start = pos - range[0];
+    } else {
+      start = pos;
+    }
+    // Then we add the ranges on at a time, incrementing the current
+    // position to be after the last block each time.  The position
+    // always points to the start of a block.
+    while (pos < to()) {
+      length = canonrange.get(start, '\0', range);
+      if (length == 0) {
+        range[0] = start;
+      } else {
+        ASSERT_EQ(1, length);
+      }
+      ASSERT((range[0] & kStartMarker) != 0);
+      // The start point of a block contains the distance to the end
+      // of the range.
+      int block_end = start + (range[0] & kPayloadMask) - 1;
+      int end = (block_end > to()) ? to() : block_end;
+      length = uncanonicalize.get(start, '\0', range);
+      for (int i = 0; i < length; i++) {
+        uc32 c = range[i];
+        uc16 range_from = c + (pos - start);
+        uc16 range_to = c + (end - start);
+        if (!(from() <= range_from && range_to <= to()))
+          ranges->Add(CharacterRange(range_from, range_to));
+      }
+      start = pos = block_end + 1;
+    }
+  } else {
+    // TODO(plesner) when we've fixed the 2^11 bug in unibrow.
+  }
+}
+
+
+// -------------------------------------------------------------------
+// Interest propagation
+
+
+RegExpNode* RegExpNode::GetSibling(NodeInfo* info) {
+  for (int i = 0; i < siblings_.length(); i++) {
+    RegExpNode* sibling = siblings_.Get(i);
+    if (sibling->info()->SameInterests(info))
+      return sibling;
+  }
+  return NULL;
+}
+
+
+template <class C>
+static RegExpNode* PropagateToEndpoint(C* node, NodeInfo* info) {
+  RegExpNode* sibling = node->GetSibling(info);
+  if (sibling != NULL) return sibling;
+  node->EnsureSiblings();
+  sibling = new C(*node);
+  sibling->info()->AdoptInterests(info);
+  node->AddSibling(sibling);
+  return sibling;
+}
+
+
+RegExpNode* ActionNode::PropagateInterest(NodeInfo* info) {
+  RegExpNode* sibling = GetSibling(info);
+  if (sibling != NULL) return sibling;
+  EnsureSiblings();
+  ActionNode* action = new ActionNode(*this);
+  action->info()->AdoptInterests(info);
+  AddSibling(action);
+  action->set_on_success(action->on_success()->PropagateInterest(info));
+  return action;
+}
+
+
+RegExpNode* ChoiceNode::PropagateInterest(NodeInfo* info) {
+  RegExpNode* sibling = GetSibling(info);
+  if (sibling != NULL) return sibling;
+  EnsureSiblings();
+  ChoiceNode* choice = new ChoiceNode(*this);
+  choice->info()->AdoptInterests(info);
+  AddSibling(choice);
+  ZoneList<GuardedAlternative>* old_alternatives = alternatives();
+  int count = old_alternatives->length();
+  choice->alternatives_ = new ZoneList<GuardedAlternative>(count);
+  for (int i = 0; i < count; i++) {
+    GuardedAlternative alternative = old_alternatives->at(i);
+    alternative.set_node(alternative.node()->PropagateInterest(info));
+    choice->alternatives()->Add(alternative);
+  }
+  return choice;
+}
+
+
+RegExpNode* EndNode::PropagateInterest(NodeInfo* info) {
+  return PropagateToEndpoint(this, info);
+}
+
+
+RegExpNode* BackReferenceNode::PropagateInterest(NodeInfo* info) {
+  return PropagateToEndpoint(this, info);
+}
+
+
+RegExpNode* TextNode::PropagateInterest(NodeInfo* info) {
+  return PropagateToEndpoint(this, info);
+}
+
+
+// -------------------------------------------------------------------
+// Splay tree
+
+
+OutSet* OutSet::Extend(unsigned value) {
+  if (Get(value))
+    return this;
+  if (successors() != NULL) {
+    for (int i = 0; i < successors()->length(); i++) {
+      OutSet* successor = successors()->at(i);
+      if (successor->Get(value))
+        return successor;
+    }
+  } else {
+    successors_ = new ZoneList<OutSet*>(2);
+  }
+  OutSet* result = new OutSet(first_, remaining_);
+  result->Set(value);
+  successors()->Add(result);
+  return result;
+}
+
+
+void OutSet::Set(unsigned value) {
+  if (value < kFirstLimit) {
+    first_ |= (1 << value);
+  } else {
+    if (remaining_ == NULL)
+      remaining_ = new ZoneList<unsigned>(1);
+    if (remaining_->is_empty() || !remaining_->Contains(value))
+      remaining_->Add(value);
+  }
+}
+
+
+bool OutSet::Get(unsigned value) {
+  if (value < kFirstLimit) {
+    return (first_ & (1 << value)) != 0;
+  } else if (remaining_ == NULL) {
+    return false;
+  } else {
+    return remaining_->Contains(value);
+  }
+}
+
+
+const uc16 DispatchTable::Config::kNoKey = unibrow::Utf8::kBadChar;
+const DispatchTable::Entry DispatchTable::Config::kNoValue;
+
+
+void DispatchTable::AddRange(CharacterRange full_range, int value) {
+  CharacterRange current = full_range;
+  if (tree()->is_empty()) {
+    // If this is the first range we just insert into the table.
+    ZoneSplayTree<Config>::Locator loc;
+    ASSERT_RESULT(tree()->Insert(current.from(), &loc));
+    loc.set_value(Entry(current.from(), current.to(), empty()->Extend(value)));
+    return;
+  }
+  // First see if there is a range to the left of this one that
+  // overlaps.
+  ZoneSplayTree<Config>::Locator loc;
+  if (tree()->FindGreatestLessThan(current.from(), &loc)) {
+    Entry* entry = &loc.value();
+    // If we've found a range that overlaps with this one, and it
+    // starts strictly to the left of this one, we have to fix it
+    // because the following code only handles ranges that start on
+    // or after the start point of the range we're adding.
+    if (entry->from() < current.from() && entry->to() >= current.from()) {
+      // Snap the overlapping range in half around the start point of
+      // the range we're adding.
+      CharacterRange left(entry->from(), current.from() - 1);
+      CharacterRange right(current.from(), entry->to());
+      // The left part of the overlapping range doesn't overlap.
+      // Truncate the whole entry to be just the left part.
+      entry->set_to(left.to());
+      // The right part is the one that overlaps.  We add this part
+      // to the map and let the next step deal with merging it with
+      // the range we're adding.
+      ZoneSplayTree<Config>::Locator loc;
+      ASSERT_RESULT(tree()->Insert(right.from(), &loc));
+      loc.set_value(Entry(right.from(),
+                          right.to(),
+                          entry->out_set()));
+    }
+  }
+  while (current.is_valid()) {
+    if (tree()->FindLeastGreaterThan(current.from(), &loc) &&
+        (loc.value().from() <= current.to()) &&
+        (loc.value().to() >= current.from())) {
+      Entry* entry = &loc.value();
+      // We have overlap.  If there is space between the start point of
+      // the range we're adding and where the overlapping range starts
+      // then we have to add a range covering just that space.
+      if (current.from() < entry->from()) {
+        ZoneSplayTree<Config>::Locator ins;
+        ASSERT_RESULT(tree()->Insert(current.from(), &ins));
+        ins.set_value(Entry(current.from(),
+                            entry->from() - 1,
+                            empty()->Extend(value)));
+        current.set_from(entry->from());
+      }
+      ASSERT_EQ(current.from(), entry->from());
+      // If the overlapping range extends beyond the one we want to add
+      // we have to snap the right part off and add it separately.
+      if (entry->to() > current.to()) {
+        ZoneSplayTree<Config>::Locator ins;
+        ASSERT_RESULT(tree()->Insert(current.to() + 1, &ins));
+        ins.set_value(Entry(current.to() + 1,
+                            entry->to(),
+                            entry->out_set()));
+        entry->set_to(current.to());
+      }
+      ASSERT(entry->to() <= current.to());
+      // The overlapping range is now completely contained by the range
+      // we're adding so we can just update it and move the start point
+      // of the range we're adding just past it.
+      entry->AddValue(value);
+      // Bail out if the last interval ended at 0xFFFF since otherwise
+      // adding 1 will wrap around to 0.
+      if (entry->to() == 0xFFFF)
+        break;
+      ASSERT(entry->to() + 1 > current.from());
+      current.set_from(entry->to() + 1);
+    } else {
+      // There is no overlap so we can just add the range
+      ZoneSplayTree<Config>::Locator ins;
+      ASSERT_RESULT(tree()->Insert(current.from(), &ins));
+      ins.set_value(Entry(current.from(),
+                          current.to(),
+                          empty()->Extend(value)));
+      break;
+    }
+  }
+}
+
+
+OutSet* DispatchTable::Get(uc16 value) {
+  ZoneSplayTree<Config>::Locator loc;
+  if (!tree()->FindGreatestLessThan(value, &loc))
+    return empty();
+  Entry* entry = &loc.value();
+  if (value <= entry->to())
+    return entry->out_set();
+  else
+    return empty();
+}
+
+
+// -------------------------------------------------------------------
+// Analysis
+
+
+void Analysis::EnsureAnalyzed(RegExpNode* that) {
+  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) {
+  EnsureAnalyzed(that->on_success());
+  EnsureAnalyzed(that->on_failure());
+}
+
+
+void Analysis::VisitAction(ActionNode* that) {
+  RegExpNode* next = that->on_success();
+  EnsureAnalyzed(next);
+  that->info()->determine_newline = next->info()->prev_determine_newline();
+  that->info()->determine_word = next->info()->prev_determine_word();
+  that->info()->determine_start = next->info()->prev_determine_start();
+}
+
+
+void Analysis::VisitChoice(ChoiceNode* that) {
+  NodeInfo* info = that->info();
+  for (int i = 0; i < that->alternatives()->length(); i++) {
+    RegExpNode* node = that->alternatives()->at(i).node();
+    EnsureAnalyzed(node);
+    info->determine_newline |= node->info()->prev_determine_newline();
+    info->determine_word |= node->info()->prev_determine_word();
+    info->determine_start |= node->info()->prev_determine_start();
+  }
+  if (!that->table_calculated()) {
+    DispatchTableConstructor cons(that->table());
+    cons.BuildTable(that);
+  }
+  EnsureAnalyzed(that->on_failure());
+}
+
+
+void Analysis::VisitBackReference(BackReferenceNode* that) {
+  EnsureAnalyzed(that->on_success());
+  EnsureAnalyzed(that->on_failure());
+}
+
+
+// -------------------------------------------------------------------
+// Dispatch table construction
+
+
+void DispatchTableConstructor::VisitEnd(EndNode* that) {
+  AddRange(CharacterRange::Everything());
+}
+
+
+void DispatchTableConstructor::BuildTable(ChoiceNode* node) {
+  ASSERT(!node->table_calculated());
+  node->set_being_calculated(true);
+  ZoneList<GuardedAlternative>* alternatives = node->alternatives();
+  for (int i = 0; i < alternatives->length(); i++) {
+    set_choice_index(i);
+    alternatives->at(i).node()->Accept(this);
+  }
+  node->set_being_calculated(false);
+  node->set_table_calculated(true);
+}
+
+
+class AddDispatchRange {
+ public:
+  explicit AddDispatchRange(DispatchTableConstructor* constructor)
+    : constructor_(constructor) { }
+  void Call(uc32 from, DispatchTable::Entry entry);
+ private:
+  DispatchTableConstructor* constructor_;
+};
+
+
+void AddDispatchRange::Call(uc32 from, DispatchTable::Entry entry) {
+  CharacterRange range(from, entry.to());
+  constructor_->AddRange(range);
+}
+
+
+void DispatchTableConstructor::VisitChoice(ChoiceNode* node) {
+  if (node->being_calculated())
+    return;
+  if (!node->table_calculated()) {
+    DispatchTableConstructor constructor(node->table());
+    constructor.BuildTable(node);
+  }
+  ASSERT(node->table_calculated());
+  AddDispatchRange adder(this);
+  node->table()->ForEach(&adder);
+}
+
+
+void DispatchTableConstructor::VisitBackReference(BackReferenceNode* that) {
+  // TODO(160): Find the node that we refer back to and propagate its start
+  // set back to here.  For now we just accept anything.
+  AddRange(CharacterRange::Everything());
+}
+
+
+
+static int CompareRangeByFrom(const CharacterRange* a,
+                              const CharacterRange* b) {
+  return Spaceship<uc16>(a->from(), b->from());
+}
+
+
+void DispatchTableConstructor::AddInverse(ZoneList<CharacterRange>* ranges) {
+  ranges->Sort(CompareRangeByFrom);
+  uc16 last = 0;
+  for (int i = 0; i < ranges->length(); i++) {
+    CharacterRange range = ranges->at(i);
+    if (last < range.from())
+      AddRange(CharacterRange(last, range.from() - 1));
+    if (range.to() >= last) {
+      if (range.to() == 0xFFFF) {
+        return;
+      } else {
+        last = range.to() + 1;
+      }
+    }
+  }
+  AddRange(CharacterRange(last, 0xFFFF));
+}
+
+
+void DispatchTableConstructor::VisitText(TextNode* that) {
+  TextElement elm = that->elements()->at(0);
+  switch (elm.type) {
+    case TextElement::ATOM: {
+      uc16 c = elm.data.u_atom->data()[0];
+      AddRange(CharacterRange(c, c));
+      break;
+    }
+    case TextElement::CHAR_CLASS: {
+      RegExpCharacterClass* tree = elm.data.u_char_class;
+      ZoneList<CharacterRange>* ranges = tree->ranges();
+      if (tree->is_negated()) {
+        AddInverse(ranges);
+      } else {
+        for (int i = 0; i < ranges->length(); i++)
+          AddRange(ranges->at(i));
+      }
+      break;
+    }
+    default: {
+      UNIMPLEMENTED();
+    }
+  }
+}
+
+
+void DispatchTableConstructor::VisitAction(ActionNode* that) {
+  that->on_success()->Accept(this);
+}
+
+
+Handle<FixedArray> RegExpEngine::Compile(RegExpParseResult* input,
+                                         RegExpNode** node_return,
+                                         bool ignore_case) {
+  RegExpCompiler compiler(input->capture_count, ignore_case);
+  // Wrap the body of the regexp in capture #0.
+  RegExpNode* captured_body = RegExpCapture::ToNode(input->tree,
+                                                    0,
+                                                    &compiler,
+                                                    compiler.accept(),
+                                                    compiler.backtrack());
+  // Add a .*? at the beginning, outside the body capture.
+  // Note: We could choose to not add this if the regexp is anchored at
+  //   the start of the input but I'm not sure how best to do that and
+  //   since we don't even handle ^ yet I'm saving that optimization for
+  //   later.
+  RegExpNode* node = RegExpQuantifier::ToNode(0,
+                                              RegExpQuantifier::kInfinity,
+                                              false,
+                                              new RegExpCharacterClass('*'),
+                                              &compiler,
+                                              captured_body,
+                                              compiler.backtrack());
+  if (node_return != NULL) *node_return = node;
+  Analysis analysis;
+  analysis.EnsureAnalyzed(node);
+
+  if (!FLAG_irregexp) {
+    return Handle<FixedArray>::null();
+  }
+
+#if !(defined ARM || defined __arm__ || defined __thumb__)
+  if (FLAG_irregexp_native) {  // Flag only checked in IA32 mode.
+    // TODO(lrn) Move compilation to a later point in the life-cycle
+    // of the RegExp. We don't know the type of input string yet.
+    // For now, always assume two-byte strings.
+    RegExpMacroAssemblerIA32 macro_assembler(RegExpMacroAssemblerIA32::UC16,
+                                             (input->capture_count + 1) * 2,
+                                             ignore_case);
+    return compiler.Assemble(&macro_assembler,
+                             node,
+                             input->capture_count);
+  }
+#endif
+  byte codes[1024];
+  IrregexpAssembler assembler(Vector<byte>(codes, 1024));
+  RegExpMacroAssemblerIrregexp macro_assembler(&assembler);
+  return compiler.Assemble(&macro_assembler,
+                           node,
+                           input->capture_count);
+}
+
+
 }}  // namespace v8::internal
index c05380d..d8ed043 100644 (file)
 
 namespace v8 { namespace internal {
 
+
+class RegExpMacroAssembler;
+
+
 class RegExpImpl {
  public:
   // Creates a regular expression literal in the old space.
@@ -61,10 +65,28 @@ class RegExpImpl {
   static Handle<Object> ExecGlobal(Handle<JSRegExp> regexp,
                                    Handle<String> subject);
 
+  // Stores an uncompiled RegExp pattern in the JSRegExp object.
+  // It will be compiled by JSCRE when first executed.
+  static Handle<Object> JscrePrepare(Handle<JSRegExp> re,
+                                     Handle<String> pattern,
+                                     JSRegExp::Flags flags);
+
+  // Stores a compiled RegExp pattern in the JSRegExp object.
+  // The pattern is compiled by Irregexp.
+  static Handle<Object> IrregexpPrepare(Handle<JSRegExp> re,
+                                        Handle<String> pattern,
+                                        JSRegExp::Flags flags,
+                                        Handle<FixedArray> irregexp_data);
+
+
+  // Compile the pattern using JSCRE and store the result in the
+  // JSRegExp object.
+  static Handle<Object> JscreCompile(Handle<JSRegExp> re);
+
   static Handle<Object> AtomCompile(Handle<JSRegExp> re,
                                     Handle<String> pattern,
-                                    JSRegExp::Flags flags);
-
+                                    JSRegExp::Flags flags,
+                                    Handle<String> match_pattern);
   static Handle<Object> AtomExec(Handle<JSRegExp> regexp,
                                  Handle<String> subject,
                                  Handle<Object> index);
@@ -72,47 +94,78 @@ class RegExpImpl {
   static Handle<Object> AtomExecGlobal(Handle<JSRegExp> regexp,
                                        Handle<String> subject);
 
-  static Handle<Object> JsreCompile(Handle<JSRegExp> re,
-                                    Handle<String> pattern,
-                                    JSRegExp::Flags flags);
+  static Handle<Object> JscreCompile(Handle<JSRegExp> re,
+                                     Handle<String> pattern,
+                                     JSRegExp::Flags flags);
 
-  static Handle<Object> JsreExec(Handle<JSRegExp> regexp,
-                                 Handle<String> subject,
-                                 Handle<Object> index);
+  // Execute a compiled JSCRE pattern.
+  static Handle<Object> JscreExec(Handle<JSRegExp> regexp,
+                                  Handle<String> subject,
+                                  Handle<Object> index);
 
-  static Handle<Object> JsreExecGlobal(Handle<JSRegExp> regexp,
-                                       Handle<String> subject);
+  // Execute an Irregexp bytecode pattern.
+  static Handle<Object> IrregexpExec(Handle<JSRegExp> regexp,
+                                     Handle<String> subject,
+                                     Handle<Object> index);
+
+  static Handle<Object> JscreExecGlobal(Handle<JSRegExp> regexp,
+                                        Handle<String> subject);
+
+  static Handle<Object> IrregexpExecGlobal(Handle<JSRegExp> regexp,
+                                           Handle<String> subject);
 
   static void NewSpaceCollectionPrologue();
   static void OldSpaceCollectionPrologue();
 
- private:
   // Converts a source string to a 16 bit flat string.  The string
   // will be either sequential or it will be a SlicedString backed
   // by a flat string.
   static Handle<String> StringToTwoByte(Handle<String> pattern);
   static Handle<String> CachedStringToTwoByte(Handle<String> pattern);
 
+  static const int kIrregexpImplementationIndex = 0;
+  static const int kIrregexpNumberOfCapturesIndex = 1;
+  static const int kIrregexpNumberOfRegistersIndex = 2;
+  static const int kIrregexpCodeIndex = 3;
+  static const int kIrregexpDataLength = 4;
+
+  static const int kJscreNumberOfCapturesIndex = 0;
+  static const int kJscreInternalIndex = 1;
+  static const int kJscreDataLength = 2;
+
+ private:
   static String* last_ascii_string_;
   static String* two_byte_cached_string_;
 
-  // Returns the caputure from the re.
-  static int JsreCapture(Handle<JSRegExp> re);
-  static ByteArray* JsreInternal(Handle<JSRegExp> re);
+  static int JscreNumberOfCaptures(Handle<JSRegExp> re);
+  static ByteArray* JscreInternal(Handle<JSRegExp> re);
+
+  static int IrregexpNumberOfCaptures(Handle<JSRegExp> re);
+  static int IrregexpNumberOfRegisters(Handle<JSRegExp> re);
+  static Handle<ByteArray> IrregexpCode(Handle<JSRegExp> re);
 
   // Call jsRegExpExecute once
-  static Handle<Object> JsreExecOnce(Handle<JSRegExp> regexp,
-                                     int num_captures,
-                                     Handle<String> subject,
-                                     int previous_index,
-                                     const uc16* utf8_subject,
-                                     int* ovector,
-                                     int ovector_length);
+  static Handle<Object> JscreExecOnce(Handle<JSRegExp> regexp,
+                                      int num_captures,
+                                      Handle<String> subject,
+                                      int previous_index,
+                                      const uc16* utf8_subject,
+                                      int* ovector,
+                                      int ovector_length);
+
+  static Handle<Object> IrregexpExecOnce(Handle<JSRegExp> regexp,
+                                         int num_captures,
+                                         Handle<String> subject16,
+                                         int previous_index,
+                                         int* ovector,
+                                         int ovector_length);
 
   // Set the subject cache.  The previous string buffer is not deleted, so the
   // caller should ensure that it doesn't leak.
-  static void SetSubjectCache(String* subject, char* utf8_subject,
-                              int uft8_length, int character_position,
+  static void SetSubjectCache(String* subject,
+                              char* utf8_subject,
+                              int uft8_length,
+                              int character_position,
                               int utf8_position);
 
   // A one element cache of the last utf8_subject string and its length.  The
@@ -125,6 +178,599 @@ class RegExpImpl {
 };
 
 
+class CharacterRange {
+ public:
+  CharacterRange() : from_(0), to_(0) { }
+  // For compatibility with the CHECK_OK macro
+  CharacterRange(void* null) { ASSERT_EQ(NULL, null); }  //NOLINT
+  CharacterRange(uc16 from, uc16 to)
+    : from_(from),
+      to_(to) {
+  }
+  static void AddClassEscape(uc16 type, ZoneList<CharacterRange>* ranges);
+  static inline CharacterRange Singleton(uc16 value) {
+    return CharacterRange(value, value);
+  }
+  static inline CharacterRange Range(uc16 from, uc16 to) {
+    ASSERT(from <= to);
+    return CharacterRange(from, to);
+  }
+  static inline CharacterRange Everything() {
+    return CharacterRange(0, 0xFFFF);
+  }
+  bool Contains(uc16 i) { return from_ <= i && i <= to_; }
+  uc16 from() const { return from_; }
+  void set_from(uc16 value) { from_ = value; }
+  uc16 to() const { return to_; }
+  void set_to(uc16 value) { to_ = value; }
+  bool is_valid() { return from_ <= to_; }
+  bool IsSingleton() { return (from_ == to_); }
+  void AddCaseEquivalents(ZoneList<CharacterRange>* ranges);
+  static const int kRangeCanonicalizeMax = 0x200;
+  static const int kStartMarker = (1 << 24);
+  static const int kPayloadMask = (1 << 24) - 1;
+ private:
+  uc16 from_;
+  uc16 to_;
+};
+
+
+template <typename Node, class Callback>
+static void DoForEach(Node* node, Callback* callback);
+
+
+// A zone splay tree.  The config type parameter encapsulates the
+// different configurations of a concrete splay tree:
+//
+//   typedef Key: the key type
+//   typedef Value: the value type
+//   static const kNoKey: the dummy key used when no key is set
+//   static const kNoValue: the dummy value used to initialize nodes
+//   int (Compare)(Key& a, Key& b) -> {-1, 0, 1}: comparison function
+//
+template <typename Config>
+class ZoneSplayTree : public ZoneObject {
+ public:
+  typedef typename Config::Key Key;
+  typedef typename Config::Value Value;
+
+  class Locator;
+
+  ZoneSplayTree() : root_(NULL) { }
+
+  // Inserts the given key in this tree with the given value.  Returns
+  // true if a node was inserted, otherwise false.  If found the locator
+  // is enabled and provides access to the mapping for the key.
+  bool Insert(const Key& key, Locator* locator);
+
+  // Looks up the key in this tree and returns true if it was found,
+  // otherwise false.  If the node is found the locator is enabled and
+  // provides access to the mapping for the key.
+  bool Find(const Key& key, Locator* locator);
+
+  // Finds the mapping with the greatest key less than or equal to the
+  // given key.
+  bool FindGreatestLessThan(const Key& key, Locator* locator);
+
+  // Find the mapping with the greatest key in this tree.
+  bool FindGreatest(Locator* locator);
+
+  // Finds the mapping with the least key greater than or equal to the
+  // given key.
+  bool FindLeastGreaterThan(const Key& key, Locator* locator);
+
+  // Find the mapping with the least key in this tree.
+  bool FindLeast(Locator* locator);
+
+  // Remove the node with the given key from the tree.
+  bool Remove(const Key& key);
+
+  bool is_empty() { return root_ == NULL; }
+
+  // Perform the splay operation for the given key. Moves the node with
+  // the given key to the top of the tree.  If no node has the given
+  // key, the last node on the search path is moved to the top of the
+  // tree.
+  void Splay(const Key& key);
+
+  class Node : public ZoneObject {
+   public:
+    Node(const Key& key, const Value& value)
+      : key_(key),
+        value_(value),
+        left_(NULL),
+        right_(NULL) { }
+     Key key() { return key_; }
+     Value value() { return value_; }
+     Node* left() { return left_; }
+     Node* right() { return right_; }
+   private:
+    friend class ZoneSplayTree;
+    friend class Locator;
+    Key key_;
+    Value value_;
+    Node* left_;
+    Node* right_;
+  };
+
+  // A locator provides access to a node in the tree without actually
+  // exposing the node.
+  class Locator {
+   public:
+    explicit Locator(Node* node) : node_(node) { }
+    Locator() : node_(NULL) { }
+    const Key& key() { return node_->key_; }
+    Value& value() { return node_->value_; }
+    void set_value(const Value& value) { node_->value_ = value; }
+    inline void bind(Node* node) { node_ = node; }
+   private:
+    Node* node_;
+  };
+
+  template <class Callback>
+  void ForEach(Callback* c) {
+    DoForEach<typename ZoneSplayTree<Config>::Node, Callback>(root_, c);
+  }
+
+ private:
+  Node* root_;
+};
+
+
+// A set of unsigned integers that behaves especially well on small
+// integers (< 32).  May do zone-allocation.
+class OutSet: public ZoneObject {
+ public:
+  OutSet() : first_(0), remaining_(NULL), successors_(NULL) { }
+  OutSet* Extend(unsigned value);
+  bool Get(unsigned value);
+  static const unsigned kFirstLimit = 32;
+ private:
+
+  // 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(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.
+  ZoneList<OutSet*>* successors() { return successors_; }
+
+  OutSet(uint32_t first, ZoneList<unsigned>* remaining)
+    : first_(first), remaining_(remaining), successors_(NULL) { }
+  uint32_t first_;
+  ZoneList<unsigned>* remaining_;
+  ZoneList<OutSet*>* successors_;
+};
+
+
+// A mapping from integers, specified as ranges, to a set of integers.
+// Used for mapping character ranges to choices.
+class DispatchTable {
+ public:
+  class Entry {
+   public:
+    Entry()
+      : from_(0), to_(0), out_set_(NULL) { }
+    Entry(uc16 from, uc16 to, OutSet* out_set)
+      : from_(from), to_(to), out_set_(out_set) { }
+    uc16 from() { return from_; }
+    uc16 to() { return to_; }
+    void set_to(uc16 value) { to_ = value; }
+    void AddValue(int value) { out_set_ = out_set_->Extend(value); }
+    OutSet* out_set() { return out_set_; }
+   private:
+    uc16 from_;
+    uc16 to_;
+    OutSet* out_set_;
+  };
+
+  class Config {
+   public:
+    typedef uc16 Key;
+    typedef Entry Value;
+    static const uc16 kNoKey;
+    static const Entry kNoValue;
+    static inline int Compare(uc16 a, uc16 b) {
+      if (a == b)
+        return 0;
+      else if (a < b)
+        return -1;
+      else
+        return 1;
+    }
+  };
+
+  void AddRange(CharacterRange range, int value);
+  OutSet* Get(uc16 value);
+  void Dump();
+
+  template <typename Callback>
+  void ForEach(Callback* callback) { return tree()->ForEach(callback); }
+ private:
+  // There can't be a static empty set since it allocates its
+  // successors in a zone and caches them.
+  OutSet* empty() { return &empty_; }
+  OutSet empty_;
+  ZoneSplayTree<Config>* tree() { return &tree_; }
+  ZoneSplayTree<Config> tree_;
+};
+
+
+#define FOR_EACH_NODE_TYPE(VISIT)                                    \
+  VISIT(End)                                                         \
+  VISIT(Action)                                                      \
+  VISIT(Choice)                                                      \
+  VISIT(BackReference)                                               \
+  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 TextElement {
+ public:
+  enum Type {UNINITIALIZED, ATOM, CHAR_CLASS};
+  TextElement() : type(UNINITIALIZED) { }
+  explicit TextElement(Type t) : type(t) { }
+  static TextElement Atom(RegExpAtom* atom);
+  static TextElement CharClass(RegExpCharacterClass* char_class);
+  Type type;
+  union {
+    RegExpAtom* u_atom;
+    RegExpCharacterClass* u_char_class;
+  } data;
+};
+
+
+struct NodeInfo {
+  NodeInfo()
+    : being_analyzed(false),
+      been_analyzed(false),
+      determine_word(false),
+      determine_newline(false),
+      determine_start(false),
+      follows_word_interest(false),
+      follows_newline_interest(false),
+      follows_start_interest(false) { }
+  bool SameInterests(NodeInfo* that) {
+    return (follows_word_interest == that->follows_word_interest)
+        && (follows_newline_interest == that->follows_newline_interest)
+        && (follows_start_interest == that->follows_start_interest);
+  }
+  void AdoptInterests(NodeInfo* that) {
+    follows_word_interest = that->follows_word_interest;
+    follows_newline_interest = that->follows_newline_interest;
+    follows_start_interest = that->follows_start_interest;
+  }
+  bool prev_determine_word() {
+    return determine_word || follows_word_interest;
+  }
+  bool prev_determine_newline() {
+    return determine_newline || follows_newline_interest;
+  }
+  bool prev_determine_start() {
+    return determine_start || follows_start_interest;
+  }
+  bool being_analyzed: 1;
+  bool been_analyzed: 1;
+  bool determine_word: 1;
+  bool determine_newline: 1;
+  bool determine_start: 1;
+  bool follows_word_interest: 1;
+  bool follows_newline_interest: 1;
+  bool follows_start_interest: 1;
+};
+
+
+STATIC_CHECK(sizeof(NodeInfo) <= sizeof(int));  // NOLINT
+
+
+class SiblingList {
+ public:
+  SiblingList() : list_(NULL) { }
+  int length() {
+    return list_ == NULL ? 0 : list_->length();
+  }
+  void Ensure(RegExpNode* parent) {
+    if (list_ == NULL) {
+      list_ = new ZoneList<RegExpNode*>(2);
+      list_->Add(parent);
+    }
+  }
+  void Add(RegExpNode* node) { list_->Add(node); }
+  RegExpNode* Get(int index) { return list_->at(index); }
+ private:
+  ZoneList<RegExpNode*>* list_;
+};
+
+
+class RegExpNode: public ZoneObject {
+ public:
+  virtual ~RegExpNode() { }
+  virtual void Accept(NodeVisitor* visitor) = 0;
+  // Generates a goto to this node or actually generates the code at this point.
+  // Until the implementation is complete we will return true for success and
+  // false for failure.
+  virtual bool GoTo(RegExpCompiler* compiler);
+  Label* label();
+
+  // Until the implementation is complete we will return true for success and
+  // false for failure.
+  virtual bool Emit(RegExpCompiler* compiler) = 0;
+  virtual RegExpNode* PropagateInterest(NodeInfo* info) = 0;
+  NodeInfo* info() { return &info_; }
+  virtual bool IsBacktrack() { return false; }
+  RegExpNode* GetSibling(NodeInfo* info);
+  void EnsureSiblings() { siblings_.Ensure(this); }
+  void AddSibling(RegExpNode* node) { siblings_.Add(node); }
+ protected:
+  inline void Bind(RegExpMacroAssembler* macro);
+ private:
+  Label label_;
+  NodeInfo info_;
+  SiblingList siblings_;
+};
+
+
+class SeqRegExpNode: public RegExpNode {
+ public:
+  explicit SeqRegExpNode(RegExpNode* on_success)
+    : on_success_(on_success) { }
+  RegExpNode* on_success() { return on_success_; }
+  void set_on_success(RegExpNode* node) { on_success_ = node; }
+  virtual bool Emit(RegExpCompiler* compiler) { return false; }
+ private:
+  RegExpNode* on_success_;
+};
+
+
+class ActionNode: public SeqRegExpNode {
+ public:
+  enum Type {
+    STORE_REGISTER,
+    INCREMENT_REGISTER,
+    STORE_POSITION,
+    SAVE_POSITION,
+    RESTORE_POSITION,
+    BEGIN_SUBMATCH,
+    ESCAPE_SUBMATCH
+  };
+  static ActionNode* StoreRegister(int reg, int val, RegExpNode* on_success);
+  static ActionNode* IncrementRegister(int reg, RegExpNode* on_success);
+  static ActionNode* StorePosition(int reg, RegExpNode* on_success);
+  static ActionNode* SavePosition(int reg, RegExpNode* on_success);
+  static ActionNode* RestorePosition(int reg, RegExpNode* on_success);
+  static ActionNode* BeginSubmatch(int reg, RegExpNode* on_success);
+  static ActionNode* EscapeSubmatch(int reg, RegExpNode* on_success);
+  virtual void Accept(NodeVisitor* visitor);
+  virtual bool Emit(RegExpCompiler* compiler);
+  virtual RegExpNode* PropagateInterest(NodeInfo* info);
+ private:
+  union {
+    struct {
+      int reg;
+      int value;
+    } u_store_register;
+    struct {
+      int reg;
+    } u_increment_register;
+    struct {
+      int reg;
+    } u_position_register;
+    struct {
+      int reg;
+    } u_submatch_stack_pointer_register;
+  } data_;
+  ActionNode(Type type, RegExpNode* on_success)
+    : SeqRegExpNode(on_success),
+      type_(type) { }
+  Type type_;
+  friend class DotPrinter;
+};
+
+
+class TextNode: public SeqRegExpNode {
+ public:
+  TextNode(ZoneList<TextElement>* elms,
+           RegExpNode* on_success,
+           RegExpNode* on_failure)
+    : SeqRegExpNode(on_success),
+      on_failure_(on_failure),
+      elms_(elms) { }
+  virtual void Accept(NodeVisitor* visitor);
+  virtual RegExpNode* PropagateInterest(NodeInfo* info);
+  RegExpNode* on_failure() { return on_failure_; }
+  virtual bool Emit(RegExpCompiler* compiler);
+  ZoneList<TextElement>* elements() { return elms_; }
+ private:
+  RegExpNode* on_failure_;
+  ZoneList<TextElement>* elms_;
+};
+
+
+class BackReferenceNode: public SeqRegExpNode {
+ public:
+  BackReferenceNode(int start_reg,
+                    int end_reg,
+                    RegExpNode* on_success,
+                    RegExpNode* on_failure)
+    : SeqRegExpNode(on_success),
+      on_failure_(on_failure),
+      start_reg_(start_reg),
+      end_reg_(end_reg) { }
+  virtual void Accept(NodeVisitor* visitor);
+  RegExpNode* on_failure() { return on_failure_; }
+  int start_register() { return start_reg_; }
+  int end_register() { return end_reg_; }
+  virtual bool Emit(RegExpCompiler* compiler);
+  virtual RegExpNode* PropagateInterest(NodeInfo* info);
+ private:
+  RegExpNode* on_failure_;
+  int start_reg_;
+  int end_reg_;
+};
+
+
+class EndNode: public RegExpNode {
+ public:
+  enum Action { ACCEPT, BACKTRACK };
+  explicit EndNode(Action action) : action_(action) { }
+  virtual void Accept(NodeVisitor* visitor);
+  virtual bool Emit(RegExpCompiler* compiler);
+  virtual RegExpNode* PropagateInterest(NodeInfo* info);
+  virtual bool IsBacktrack() { return action_ == BACKTRACK; }
+  virtual bool GoTo(RegExpCompiler* compiler);
+ private:
+  Action action_;
+};
+
+
+class Guard: public ZoneObject {
+ 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_;
+};
+
+
+class GuardedAlternative {
+ public:
+  explicit GuardedAlternative(RegExpNode* node) : node_(node), guards_(NULL) { }
+  void AddGuard(Guard* guard);
+  RegExpNode* node() { return node_; }
+  void set_node(RegExpNode* node) { node_ = node; }
+  ZoneList<Guard*>* guards() { return guards_; }
+ private:
+  RegExpNode* node_;
+  ZoneList<Guard*>* guards_;
+};
+
+
+class ChoiceNode: public RegExpNode {
+ public:
+  explicit ChoiceNode(int expected_size, RegExpNode* on_failure)
+    : on_failure_(on_failure),
+      alternatives_(new ZoneList<GuardedAlternative>(expected_size)),
+      table_calculated_(false),
+      being_calculated_(false) { }
+  virtual void Accept(NodeVisitor* visitor);
+  void AddAlternative(GuardedAlternative node) { alternatives()->Add(node); }
+  ZoneList<GuardedAlternative>* alternatives() { return alternatives_; }
+  DispatchTable* table() { return &table_; }
+  RegExpNode* on_failure() { return on_failure_; }
+  virtual bool Emit(RegExpCompiler* compiler);
+  virtual RegExpNode* PropagateInterest(NodeInfo* info);
+  bool table_calculated() { return table_calculated_; }
+  void set_table_calculated(bool b) { table_calculated_ = b; }
+  bool being_calculated() { return being_calculated_; }
+  void set_being_calculated(bool b) { being_calculated_ = b; }
+ private:
+  void GenerateGuard(RegExpMacroAssembler* macro_assembler,
+                     Guard *guard,
+                     Label* on_failure);
+  RegExpNode* on_failure_;
+  ZoneList<GuardedAlternative>* alternatives_;
+  DispatchTable table_;
+  bool table_calculated_;
+  bool being_calculated_;
+};
+
+
+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
+};
+
+
+// Node visitor used to add the start set of the alternatives to the
+// dispatch table of a choice node.
+class DispatchTableConstructor: public NodeVisitor {
+ public:
+  explicit DispatchTableConstructor(DispatchTable* table)
+    : table_(table),
+      choice_index_(-1) { }
+
+  void BuildTable(ChoiceNode* node);
+
+  void AddRange(CharacterRange range) {
+    table()->AddRange(range, choice_index_);
+  }
+
+  void AddInverse(ZoneList<CharacterRange>* ranges);
+
+#define DECLARE_VISIT(Type)                                          \
+  virtual void Visit##Type(Type##Node* that);
+FOR_EACH_NODE_TYPE(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+  DispatchTable* table() { return table_; }
+  void set_choice_index(int value) { choice_index_ = value; }
+
+ protected:
+  DispatchTable *table_;
+  int choice_index_;
+};
+
+
+class Analysis: public NodeVisitor {
+ public:
+  void EnsureAnalyzed(RegExpNode* node);
+
+#define DECLARE_VISIT(Type)                                          \
+  virtual void Visit##Type(Type##Node* that);
+FOR_EACH_NODE_TYPE(DECLARE_VISIT)
+#undef DECLARE_VISIT
+};
+
+
+struct RegExpParseResult {
+  RegExpTree* tree;
+  bool has_character_escapes;
+  Handle<String> error;
+  int capture_count;
+};
+
+
+class RegExpEngine: public AllStatic {
+ public:
+  static Handle<FixedArray> Compile(RegExpParseResult* input,
+                                    RegExpNode** node_return,
+                                    bool ignore_case);
+  static void DotPrint(const char* label, RegExpNode* node);
+};
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_JSREGEXP_H_
index a185af3..80094fb 100644 (file)
@@ -90,11 +90,18 @@ void List<T, P>::Iterate(void (*callback)(T* x)) {
 
 
 template<typename T, class P>
+bool List<T, P>::Contains(const T& elm) {
+  for (int i = 0; i < length_; i++) {
+    if (data_[i] == elm)
+      return true;
+  }
+  return false;
+}
+
+
+template<typename T, class P>
 void List<T, P>::Sort(int (*cmp)(const T* x, const T* y)) {
-  qsort(data_,
-        length_,
-        sizeof(T),
-        reinterpret_cast<int (*)(const void*, const void*)>(cmp));
+  ToVector().Sort(cmp);
 #ifdef DEBUG
   for (int i = 1; i < length_; i++)
     ASSERT(cmp(&data_[i - 1], &data_[i]) <= 0);
@@ -103,6 +110,12 @@ void List<T, P>::Sort(int (*cmp)(const T* x, const T* y)) {
 
 
 template<typename T, class P>
+void List<T, P>::Sort() {
+  Sort(PointerSpaceship<T>);
+}
+
+
+template<typename T, class P>
 void List<T, P>::Initialize(int capacity) {
   ASSERT(capacity >= 0);
   data_ = (capacity > 0) ? NewData(capacity) : NULL;
index 34b18fb..2f8aa90 100644 (file)
@@ -46,6 +46,7 @@ namespace v8 { namespace internal {
 template <typename T, class P>
 class List {
  public:
+
   INLINE(explicit List(int capacity)) { Initialize(capacity); }
   INLINE(~List()) { DeleteData(data_); }
 
@@ -67,6 +68,8 @@ class List {
 
   Vector<T> ToVector() { return Vector<T>(data_, length_); }
 
+  Vector<const T> ToConstVector() { return Vector<const T>(data_, length_); }
+
   // Adds a copy of the given 'element' to the end of the list,
   // expanding the list if necessary.
   T& Add(const T& element);
@@ -92,11 +95,14 @@ class List {
   // Drops all but the first 'pos' elements from the list.
   INLINE(void Rewind(int pos));
 
+  bool Contains(const T& elm);
+
   // Iterate through all list entries, starting at index 0.
   void Iterate(void (*callback)(T* x));
 
   // Sort all list entries (using QuickSort)
   void Sort(int (*cmp)(const T* x, const T* y));
+  void Sort();
 
   INLINE(void Initialize(int capacity));
 
index f2dd3b5..1c1ffed 100644 (file)
@@ -670,7 +670,14 @@ void JSRegExp::JSRegExpVerify() {
     }
     case JSRegExp::JSCRE: {
       FixedArray* arr = FixedArray::cast(data());
-      ASSERT(arr->get(JSRegExp::kJscreDataIndex)->IsFixedArray());
+      Object* jscre_data = arr->get(JSRegExp::kJscreDataIndex);
+      ASSERT(jscre_data->IsFixedArray() || jscre_data->IsUndefined());
+      break;
+    }
+    case JSRegExp::IRREGEXP: {
+      FixedArray* arr = FixedArray::cast(data());
+      Object* jscre_data = arr->get(JSRegExp::kJscreDataIndex);
+      ASSERT(jscre_data->IsFixedArray());
       break;
     }
     default:
index 97c6819..e8c4e91 100644 (file)
@@ -279,6 +279,16 @@ bool StringShape::IsExternalTwoByte() {
 }
 
 
+uc32 FlatStringReader::Get(int index) {
+  ASSERT(0 <= index && index <= length_);
+  if (is_ascii_) {
+    return static_cast<const byte*>(start_)[index];
+  } else {
+    return static_cast<const uc16*>(start_)[index];
+  }
+}
+
+
 bool Object::IsNumber() {
   return IsSmi() || IsHeapNumber();
 }
@@ -1142,6 +1152,13 @@ Object* FixedArray::get(int index) {
 }
 
 
+void FixedArray::set(int index, Smi* value) {
+  ASSERT(reinterpret_cast<Object*>(value)->IsSmi());
+  int offset = kHeaderSize + index * kPointerSize;
+  WRITE_FIELD(this, offset, value);
+}
+
+
 void FixedArray::set(int index, Object* value) {
   ASSERT(index >= 0 && index < this->length());
   int offset = kHeaderSize + index * kPointerSize;
@@ -1747,6 +1764,7 @@ Code::Flags Code::flags() {
 
 
 void Code::set_flags(Code::Flags flags) {
+  STATIC_ASSERT(Code::NUMBER_OF_KINDS <= (kFlagsKindMask >> kFlagsKindShift)+1);
   // Make sure that all call stubs have an arguments count.
   ASSERT(ExtractKindFromFlags(flags) != CALL_IC ||
          ExtractArgumentsCountFromFlags(flags) >= 0);
@@ -2213,6 +2231,22 @@ JSRegExp::Type JSRegExp::TypeTag() {
 }
 
 
+JSRegExp::Flags JSRegExp::GetFlags() {
+  ASSERT(this->data()->IsFixedArray());
+  Object* data = this->data();
+  Smi* smi = Smi::cast(FixedArray::cast(data)->get(kFlagsIndex));
+  return Flags(smi->value());
+}
+
+
+String* JSRegExp::Pattern() {
+  ASSERT(this->data()->IsFixedArray());
+  Object* data = this->data();
+  String* pattern= String::cast(FixedArray::cast(data)->get(kSourceIndex));
+  return pattern;
+}
+
+
 Object* JSRegExp::DataAt(int index) {
   ASSERT(TypeTag() != NOT_COMPILED);
   return FixedArray::cast(data())->get(index);
index b4fe552..9b88310 100644 (file)
@@ -3501,6 +3501,57 @@ const unibrow::byte* String::ReadBlock(String* input,
 }
 
 
+FlatStringReader* FlatStringReader::top_ = NULL;
+
+
+FlatStringReader::FlatStringReader(Handle<String> str)
+  : str_(str.location()),
+    length_(str->length()),
+    prev_(top_) {
+  top_ = this;
+  RefreshState();
+}
+
+
+FlatStringReader::FlatStringReader(Vector<const char> input)
+  : str_(NULL),
+    is_ascii_(true),
+    length_(input.length()),
+    start_(input.start()),
+    prev_(top_) {
+  top_ = this;
+}
+
+
+FlatStringReader::~FlatStringReader() {
+  ASSERT_EQ(top_, this);
+  top_ = prev_;
+}
+
+
+void FlatStringReader::RefreshState() {
+  if (str_ == NULL) return;
+  Handle<String> str(str_);
+  StringShape shape(*str);
+  ASSERT(str->IsFlat(shape));
+  is_ascii_ = shape.IsAsciiRepresentation();
+  if (is_ascii_) {
+    start_ = str->ToAsciiVector().start();
+  } else {
+    start_ = str->ToUC16Vector().start();
+  }
+}
+
+
+void FlatStringReader::PostGarbageCollectionProcessing() {
+  FlatStringReader* current = top_;
+  while (current != NULL) {
+    current->RefreshState();
+    current = current->prev_;
+  }
+}
+
+
 void StringInputBuffer::Seek(unsigned pos) {
   Reset(pos, input_);
 }
index 82edc53..f6feca8 100644 (file)
@@ -1498,9 +1498,12 @@ class FixedArray: public Array {
 
   // Setter and getter for elements.
   inline Object* get(int index);
+  // Setter that uses write barrier.
   inline void set(int index, Object* value);
 
-  // Setter with barrier mode.
+  // Setter that doesn't need write barrier).
+  inline void set(int index, Smi* value);
+  // Setter with explicit barrier mode.
   inline void set(int index, Object* value, WriteBarrierMode mode);
 
   // Setters for frequently used oddballs located in old space.
@@ -2114,14 +2117,17 @@ class Code: public HeapObject {
     CALL_IC,
     STORE_IC,
     KEYED_STORE_IC,
+    // No more than eight kinds. The value currently encoded in three bits in
+    // Flags.
 
     // Pseudo-kinds.
+    REGEXP = BUILTIN,
     FIRST_IC_KIND = LOAD_IC,
     LAST_IC_KIND = KEYED_STORE_IC
   };
 
   enum {
-    NUMBER_OF_KINDS = LAST_IC_KIND + 1
+    NUMBER_OF_KINDS = KEYED_STORE_IC + 1
   };
 
   // A state indicates that inline cache in this Code object contains
@@ -2272,7 +2278,6 @@ class Code: public HeapObject {
   static const int kFlagsTypeMask           = 0x000001C0;  // 111000000
   static const int kFlagsArgumentsCountMask = 0xFFFFFE00;
 
-
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(Code);
 };
@@ -2912,7 +2917,13 @@ class JSValue: public JSObject {
 // Regular expressions
 class JSRegExp: public JSObject {
  public:
-  enum Type { NOT_COMPILED, JSCRE, ATOM };
+  // Meaning of Type:
+  // NOT_COMPILED: Initial value. No data has been stored in the JSRegExp yet.
+  // JSCRE: A complex RegExp for JSCRE
+  // ATOM: A simple string to match against using an indexOf operation.
+  // IRREGEXP: Compiled with Irregexp.
+  // IRREGEXP_NATIVE: Compiled to native code with Irregexp.
+  enum Type { NOT_COMPILED, JSCRE, ATOM, IRREGEXP, IRREGEXP_NATIVE };
   enum Flag { NONE = 0, GLOBAL = 1, IGNORE_CASE = 2, MULTILINE = 4 };
 
   class Flags {
@@ -2929,6 +2940,8 @@ class JSRegExp: public JSObject {
   DECL_ACCESSORS(data, Object)
 
   inline Type TypeTag();
+  inline Flags GetFlags();
+  inline String* Pattern();
   inline Object* DataAt(int index);
 
   static inline JSRegExp* cast(Object* obj);
@@ -2945,10 +2958,11 @@ class JSRegExp: public JSObject {
   static const int kTagIndex = 0;
   static const int kSourceIndex = kTagIndex + 1;
   static const int kFlagsIndex = kSourceIndex + 1;
-  // These two are the same since the same entry is shared for
+  // These three are the same since the same entry is shared for
   // different purposes in different types of regexps.
   static const int kAtomPatternIndex = kFlagsIndex + 1;
   static const int kJscreDataIndex = kFlagsIndex + 1;
+  static const int kIrregexpDataIndex = kFlagsIndex + 1;
   static const int kDataSize = kAtomPatternIndex + 1;
 };
 
@@ -3578,6 +3592,28 @@ class ExternalTwoByteString: public ExternalString {
 };
 
 
+// A flat string reader provides random access to the contents of a
+// string independent of the character width of the string.  The handle
+// must be valid as long as the reader is being used.
+class FlatStringReader BASE_EMBEDDED {
+ public:
+  explicit FlatStringReader(Handle<String> str);
+  explicit FlatStringReader(Vector<const char> input);
+  ~FlatStringReader();
+  void RefreshState();
+  inline uc32 Get(int index);
+  int length() { return length_; }
+  static void PostGarbageCollectionProcessing();
+ private:
+  String** str_;
+  bool is_ascii_;
+  int length_;
+  const void* start_;
+  FlatStringReader* prev_;
+  static FlatStringReader* top_;
+};
+
+
 // Note that StringInputBuffers are not valid across a GC!  To fix this
 // it would have to store a String Handle instead of a String* and
 // AsciiStringReadBlock would have to be modified to use memcpy.
index bcc439f..ff9bbdc 100644 (file)
@@ -34,6 +34,7 @@
 #include "runtime.h"
 #include "parser.h"
 #include "scopes.h"
+#include "string-stream.h"
 
 namespace v8 { namespace internal {
 
@@ -227,6 +228,334 @@ class Parser {
 };
 
 
+template <typename T, int initial_size>
+class BufferedZoneList {
+ public:
+
+  BufferedZoneList() :
+    list_(NULL), last_(NULL) {}
+
+  // Adds element at end of list. This element is buffered and can
+  // be read using last() or removed using RemoveLast until a new Add or until
+  // RemoveLast or GetList has been called.
+  void Add(T* value) {
+    if (last_ != NULL) {
+      if (list_ == NULL) {
+        list_ = new ZoneList<T*>(initial_size);
+      }
+      list_->Add(last_);
+    }
+    last_ = value;
+  }
+
+  T* last() {
+    ASSERT(last_ != NULL);
+    return last_;
+  }
+
+  T* RemoveLast() {
+    ASSERT(last_ != NULL);
+    T* result = last_;
+    if (list_ != NULL && list_->length() > 0)
+      last_ = list_->RemoveLast();
+    else
+      last_ = NULL;
+    return result;
+  }
+
+  T* Get(int i) {
+    ASSERT(0 <= i && i < length());
+    if (list_ == NULL) {
+      ASSERT_EQ(0, i);
+      return last_;
+    } else {
+      if (i == list_->length()) {
+        ASSERT(last_ != NULL);
+        return last_;
+      } else {
+        return list_->at(i);
+      }
+    }
+  }
+
+  void Clear() {
+    list_ = NULL;
+    last_ = NULL;
+  }
+
+  int length() {
+    int length = (list_ == NULL) ? 0 : list_->length();
+    return length + ((last_ == NULL) ? 0 : 1);
+  }
+
+  ZoneList<T*>* GetList() {
+    if (list_ == NULL) {
+      list_ = new ZoneList<T*>(initial_size);
+    }
+    if (last_ != NULL) {
+      list_->Add(last_);
+      last_ = NULL;
+    }
+    return list_;
+  }
+
+ private:
+  ZoneList<T*>* list_;
+  T* last_;
+};
+
+// Accumulates RegExp atoms and assertions into lists of terms and alternatives.
+class RegExpBuilder {
+ public:
+  RegExpBuilder();
+  void AddCharacter(uc16 character);
+  // "Adds" an empty expression. Does nothing except consume a
+  // following quantifier
+  void AddEmpty();
+  void AddAtom(RegExpTree* tree);
+  void AddAssertion(RegExpTree* tree);
+  void NewAlternative();  // '|'
+  void AddQuantifierToAtom(int min, int max, bool is_greedy);
+  RegExpTree* ToRegExp();
+ private:
+  void FlushCharacters();
+  void FlushText();
+  void FlushTerms();
+  bool pending_empty_;
+  ZoneList<uc16>* characters_;
+  BufferedZoneList<RegExpTree, 2> terms_;
+  BufferedZoneList<RegExpTree, 2> text_;
+  BufferedZoneList<RegExpTree, 2> alternatives_;
+#ifdef DEBUG
+  enum {ADD_NONE, ADD_CHAR, ADD_TERM, ADD_ASSERT, ADD_ATOM} last_added_;
+#define LAST(x) last_added_ = x;
+#else
+#define LAST(x)
+#endif
+};
+
+
+RegExpBuilder::RegExpBuilder()
+  : pending_empty_(false), characters_(NULL), terms_(), alternatives_()
+#ifdef DEBUG
+  , last_added_(ADD_NONE)
+#endif
+  {}
+
+
+void RegExpBuilder::FlushCharacters() {
+  pending_empty_ = false;
+  if (characters_ != NULL) {
+    RegExpTree* atom = new RegExpAtom(characters_->ToConstVector());
+    characters_ = NULL;
+    text_.Add(atom);
+    LAST(ADD_ATOM);
+  }
+}
+
+
+void RegExpBuilder::FlushText() {
+  FlushCharacters();
+  int num_text = text_.length();
+  if (num_text == 0) {
+    return;
+  } else if (num_text == 1) {
+    terms_.Add(text_.last());
+  } else {
+    RegExpText* text = new RegExpText();
+    for (int i = 0; i < num_text; i++)
+      text_.Get(i)->AppendToText(text);
+    terms_.Add(text);
+  }
+  text_.Clear();
+}
+
+
+void RegExpBuilder::AddCharacter(uc16 c) {
+  pending_empty_ = false;
+  if (characters_ == NULL) {
+    characters_ = new ZoneList<uc16>(4);
+  }
+  characters_->Add(c);
+  LAST(ADD_CHAR);
+}
+
+
+void RegExpBuilder::AddEmpty() {
+  pending_empty_ = true;
+}
+
+
+void RegExpBuilder::AddAtom(RegExpTree* term) {
+  if (term->IsEmpty()) {
+    AddEmpty();
+    return;
+  }
+  if (term->IsTextElement()) {
+    FlushCharacters();
+    text_.Add(term);
+  } else {
+    FlushText();
+    terms_.Add(term);
+  }
+  LAST(ADD_ATOM);
+}
+
+
+void RegExpBuilder::AddAssertion(RegExpTree* assert) {
+  FlushText();
+  terms_.Add(assert);
+  LAST(ADD_ASSERT);
+}
+
+
+void RegExpBuilder::NewAlternative() {
+  FlushTerms();
+}
+
+
+void RegExpBuilder::FlushTerms() {
+  FlushText();
+  int num_terms = terms_.length();
+  RegExpTree* alternative;
+  if (num_terms == 0) {
+    alternative = RegExpEmpty::GetInstance();
+  } else if (num_terms == 1) {
+    alternative = terms_.last();
+  } else {
+    alternative = new RegExpAlternative(terms_.GetList());
+  }
+  alternatives_.Add(alternative);
+  terms_.Clear();
+  LAST(ADD_NONE);
+}
+
+
+RegExpTree* RegExpBuilder::ToRegExp() {
+  FlushTerms();
+  int num_alternatives = alternatives_.length();
+  if (num_alternatives == 0) {
+    return RegExpEmpty::GetInstance();
+  }
+  if (num_alternatives == 1) {
+    return alternatives_.last();
+  }
+  return new RegExpDisjunction(alternatives_.GetList());
+}
+
+
+void RegExpBuilder::AddQuantifierToAtom(int min, int max, bool is_greedy) {
+  if (pending_empty_) {
+    pending_empty_ = false;
+    return;
+  }
+  RegExpTree* atom;
+  if (characters_ != NULL) {
+    ASSERT(last_added_ == ADD_CHAR);
+    // Last atom was character.
+    Vector<const uc16> char_vector = characters_->ToConstVector();
+    int num_chars = char_vector.length();
+    if (num_chars > 1) {
+      Vector<const uc16> prefix = char_vector.SubVector(0, num_chars - 1);
+      text_.Add(new RegExpAtom(prefix));
+      char_vector = char_vector.SubVector(num_chars - 1, num_chars);
+    }
+    characters_ = NULL;
+    atom = new RegExpAtom(char_vector);
+    FlushText();
+  } else if (text_.length() > 0) {
+    ASSERT(last_added_ == ADD_ATOM);
+    atom = text_.RemoveLast();
+    FlushText();
+  } else if (terms_.length() > 0) {
+    ASSERT(last_added_ == ADD_ATOM);
+    atom = terms_.RemoveLast();
+    if (atom->IsLookahead() || atom->IsAssertion()) {
+      // Guaranteed not to match a non-empty string.
+      // Assertion as an atom can happen as, e.g., (?:\b)
+      LAST(ADD_TERM);
+      if (min == 0) {
+        return;
+      }
+      terms_.Add(atom);
+      return;
+    }
+  } else {
+    // Only call immediately after adding an atom or character!
+    UNREACHABLE();
+    return;
+  }
+  terms_.Add(new RegExpQuantifier(min, max, is_greedy, atom));
+  LAST(ADD_TERM);
+}
+
+
+class RegExpParser {
+ public:
+  RegExpParser(FlatStringReader* in,
+               Handle<String>* error,
+               bool multiline_mode);
+  RegExpTree* ParsePattern(bool* ok);
+  RegExpTree* ParseDisjunction(bool* ok);
+  RegExpTree* ParseGroup(bool* ok);
+  RegExpTree* ParseCharacterClass(bool* ok);
+
+  // Parses a {...,...} quantifier and stores the range in the given
+  // out parameters.
+  bool ParseIntervalQuantifier(int* min_out, int* max_out);
+
+  // Parses and returns a single escaped character.  The character
+  // must not be 'b' or 'B' since they are usually handle specially.
+  uc32 ParseClassCharacterEscape(bool* ok);
+
+  // Checks whether the following is a length-digit hexadecimal number,
+  // and sets the value if it is.
+  bool ParseHexEscape(int length, uc32* value);
+
+  uc32 ParseControlLetterEscape(bool* ok);
+  uc32 ParseOctalLiteral();
+
+  // Tries to parse the input as a back reference.  If successful it
+  // stores the result in the output parameter and returns true.  If
+  // it fails it will push back the characters read so the same characters
+  // can be reparsed.
+  bool ParseBackReferenceIndex(int* index_out);
+
+  CharacterRange ParseClassAtom(bool* is_char_class,
+                                ZoneList<CharacterRange>* ranges,
+                                bool* ok);
+  RegExpTree* ReportError(Vector<const char> message, bool* ok);
+  void Advance();
+  void Advance(int dist);
+  void Reset(int pos);
+
+  bool HasCharacterEscapes();
+
+  int captures_started() { return captures_ == NULL ? 0 : captures_->length(); }
+  int position() { return next_pos_ - 1; }
+
+  static const uc32 kEndMarker = (1 << 21);
+ private:
+  uc32 current() { return current_; }
+  bool has_more() { return has_more_; }
+  bool has_next() { return next_pos_ < in()->length(); }
+  uc32 Next();
+  FlatStringReader* in() { return in_; }
+  void ScanForCaptures();
+  bool CaptureAvailable(int index);
+  uc32 current_;
+  bool has_more_;
+  bool multiline_mode_;
+  int next_pos_;
+  FlatStringReader* in_;
+  Handle<String>* error_;
+  bool has_character_escapes_;
+  bool is_scanned_for_captures_;
+  ZoneList<RegExpCapture*>* captures_;
+  int capture_count_;
+};
+
+
 // A temporary scope stores information during parsing, just like
 // a plain scope.  However, temporary scopes are not kept around
 // after parsing or referenced by syntax trees so they can be stack-
@@ -3164,6 +3493,756 @@ Expression* Parser::NewThrowError(Handle<String> constructor,
 
 
 // ----------------------------------------------------------------------------
+// Regular expressions
+
+
+RegExpParser::RegExpParser(FlatStringReader* in,
+                           Handle<String>* error,
+                           bool multiline_mode)
+  : current_(kEndMarker),
+    has_more_(true),
+    multiline_mode_(multiline_mode),
+    next_pos_(0),
+    in_(in),
+    error_(error),
+    has_character_escapes_(false),
+    is_scanned_for_captures_(false),
+    captures_(NULL),
+    capture_count_(0) {
+  Advance(1);
+}
+
+
+uc32 RegExpParser::Next() {
+  if (has_next()) {
+    return in()->Get(next_pos_);
+  } else {
+    return kEndMarker;
+  }
+}
+
+
+void RegExpParser::Advance() {
+  if (next_pos_ < in()->length()) {
+    current_ = in()->Get(next_pos_);
+    next_pos_++;
+  } else {
+    current_ = kEndMarker;
+    has_more_ = false;
+  }
+}
+
+
+void RegExpParser::Reset(int pos) {
+  next_pos_ = pos;
+  Advance();
+}
+
+
+void RegExpParser::Advance(int dist) {
+  for (int i = 0; i < dist; i++)
+    Advance();
+}
+
+
+// Reports whether the parsed string atoms contain any characters that were
+// escaped in the original pattern. If not, all atoms are proper substrings
+// of the original pattern.
+bool RegExpParser::HasCharacterEscapes() {
+  return has_character_escapes_;
+}
+
+RegExpTree* RegExpParser::ReportError(Vector<const char> message, bool* ok) {
+  *ok = false;
+  *error_ = Factory::NewStringFromAscii(message, NOT_TENURED);
+  return NULL;
+}
+
+
+// Pattern ::
+//   Disjunction
+RegExpTree* RegExpParser::ParsePattern(bool* ok) {
+  RegExpTree* result = ParseDisjunction(CHECK_OK);
+  if (has_more()) {
+    ReportError(CStrVector("Unmatched ')'"), CHECK_OK);
+  }
+  return result;
+}
+
+
+bool RegExpParser::CaptureAvailable(int index) {
+  if (captures_ == NULL) return false;
+  if (index >= captures_->length()) return false;
+  RegExpCapture* capture = captures_->at(index);
+  return capture != NULL && capture->available() == CAPTURE_AVAILABLE;
+}
+
+
+// Disjunction ::
+//   Alternative
+//   Alternative | Disjunction
+// Alternative ::
+//   [empty]
+//   Term Alternative
+// Term ::
+//   Assertion
+//   Atom
+//   Atom Quantifier
+RegExpTree* RegExpParser::ParseDisjunction(bool* ok) {
+  RegExpBuilder builder;
+  int capture_start_index = captures_started();
+  while (true) {
+    switch (current()) {
+    case kEndMarker:
+    case ')':
+      return builder.ToRegExp();
+    case '|': {
+      Advance();
+      builder.NewAlternative();
+      int capture_new_alt_start_index = captures_started();
+      for (int i = capture_start_index; i < capture_new_alt_start_index; i++) {
+        RegExpCapture* capture = captures_->at(i);
+        if (capture->available() == CAPTURE_AVAILABLE) {
+          capture->set_available(CAPTURE_UNREACHABLE);
+        }
+      }
+      capture_start_index = capture_new_alt_start_index;
+      continue;
+    }
+    case '*':
+    case '+':
+    case '?':
+      ReportError(CStrVector("Nothing to repeat"), CHECK_OK);
+    case '^': {
+      Advance();
+      RegExpAssertion::Type type =
+          multiline_mode_ ? RegExpAssertion::START_OF_LINE :
+                            RegExpAssertion::START_OF_INPUT;
+      builder.AddAssertion(new RegExpAssertion(type));
+      continue;
+    }
+    case '$': {
+      Advance();
+      RegExpAssertion::Type type =
+          multiline_mode_ ? RegExpAssertion::END_OF_LINE :
+                            RegExpAssertion::END_OF_INPUT;
+      builder.AddAssertion(new RegExpAssertion(type));
+      continue;
+    }
+    case '.': {
+      Advance();
+      // everything except \x0a, \x0d, \u2028 and \u2029
+      ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2);
+      CharacterRange::AddClassEscape('.', ranges);
+      RegExpTree* atom = new RegExpCharacterClass(ranges, false);
+      builder.AddAtom(atom);
+      break;
+    }
+    case '(': {
+      RegExpTree* atom = ParseGroup(CHECK_OK);
+      builder.AddAtom(atom);
+      break;
+    }
+    case '[': {
+      RegExpTree* atom = ParseCharacterClass(CHECK_OK);
+      builder.AddAtom(atom);
+      break;
+    }
+    // Atom ::
+    //   \ AtomEscape
+    case '\\':
+      switch (Next()) {
+      case kEndMarker:
+        ReportError(CStrVector("\\ at end of pattern"), CHECK_OK);
+      case 'b':
+        Advance(2);
+        builder.AddAssertion(
+            new RegExpAssertion(RegExpAssertion::BOUNDARY));
+        continue;
+      case 'B':
+        Advance(2);
+        builder.AddAssertion(
+            new RegExpAssertion(RegExpAssertion::NON_BOUNDARY));
+        continue;
+        // AtomEscape ::
+        //   CharacterClassEscape
+        //
+        // CharacterClassEscape :: one of
+        //   d D s S w W
+      case 'd': case 'D': case 's': case 'S': case 'w': case 'W': {
+        uc32 c = Next();
+        Advance(2);
+        ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2);
+        CharacterRange::AddClassEscape(c, ranges);
+        RegExpTree* atom = new RegExpCharacterClass(ranges, false);
+        builder.AddAtom(atom);
+        goto has_read_atom;  // Avoid setting has_character_escapes_.
+      }
+      case '1': case '2': case '3': case '4': case '5': case '6':
+      case '7': case '8': case '9': {
+        int index = 0;
+        if (ParseBackReferenceIndex(&index)) {
+          if (!CaptureAvailable(index - 1)) {
+            // Prepare to ignore a following quantifier
+            builder.AddEmpty();
+            goto has_read_atom;
+          }
+          RegExpCapture* capture = captures_->at(index - 1);
+          RegExpTree* atom = new RegExpBackReference(capture);
+          builder.AddAtom(atom);
+          goto has_read_atom;  // Avoid setting has_character_escapes_.
+        }
+        uc32 first_digit = Next();
+        if (first_digit == '8' || first_digit == '9') {
+          // Treat as identity escape
+          builder.AddCharacter(first_digit);
+          Advance(2);
+          break;
+        }
+      }
+      // FALLTHROUGH
+      case '0': {
+        Advance();
+        uc32 octal = ParseOctalLiteral();
+        builder.AddCharacter(octal);
+        break;
+      }
+      // ControlEscape :: one of
+      //   f n r t v
+      case 'f':
+        Advance(2);
+        builder.AddCharacter('\f');
+        break;
+      case 'n':
+        Advance(2);
+        builder.AddCharacter('\n');
+        break;
+      case 'r':
+        Advance(2);
+        builder.AddCharacter('\r');
+        break;
+      case 't':
+        Advance(2);
+        builder.AddCharacter('\t');
+        break;
+      case 'v':
+        Advance(2);
+        builder.AddCharacter('\v');
+        break;
+      case 'c': {
+        Advance(2);
+        uc32 control = ParseControlLetterEscape(ok);
+        builder.AddCharacter(control);
+        break;
+      }
+      case 'x': {
+        Advance(2);
+        uc32 value;
+        if (ParseHexEscape(2, &value)) {
+          builder.AddCharacter(value);
+        } else {
+          builder.AddCharacter('x');
+        }
+        break;
+      }
+      case 'u': {
+        Advance(2);
+        uc32 value;
+        if (ParseHexEscape(4, &value)) {
+          builder.AddCharacter(value);
+        } else {
+          builder.AddCharacter('u');
+        }
+        break;
+      }
+      default:
+        // Identity escape.
+        builder.AddCharacter(Next());
+        Advance(2);
+        break;
+      }
+      has_character_escapes_ = true;
+      break;
+    case '{': {
+      int dummy;
+      if (ParseIntervalQuantifier(&dummy, &dummy)) {
+        ReportError(CStrVector("Nothing to repeat"), CHECK_OK);
+      }
+      // fallthrough
+    }
+    default:
+      builder.AddCharacter(current());
+      Advance();
+      break;
+    }  // end switch(current())
+
+   has_read_atom:
+    int min;
+    int max;
+    switch (current()) {
+    // QuantifierPrefix ::
+    //   *
+    //   +
+    //   ?
+    //   {
+    case '*':
+      min = 0;
+      max = RegExpQuantifier::kInfinity;
+      Advance();
+      break;
+    case '+':
+      min = 1;
+      max = RegExpQuantifier::kInfinity;
+      Advance();
+      break;
+    case '?':
+      min = 0;
+      max = 1;
+      Advance();
+      break;
+    case '{':
+      if (ParseIntervalQuantifier(&min, &max)) {
+        break;
+      } else {
+        continue;
+      }
+    default:
+      continue;
+    }
+    bool is_greedy = true;
+    if (current() == '?') {
+      is_greedy = false;
+      Advance();
+    }
+    builder.AddQuantifierToAtom(min, max, is_greedy);
+  }
+}
+
+class SourceCharacter {
+ public:
+  static bool Is(uc32 c) {
+    switch (c) {
+      // case ']': case '}':
+      // In spidermonkey and jsc these are treated as source characters
+      // so we do too.
+      case '^': case '$': case '\\': case '.': case '*': case '+':
+      case '?': case '(': case ')': case '[': case '{': case '|':
+      case RegExpParser::kEndMarker:
+        return false;
+      default:
+        return true;
+    }
+  }
+};
+
+
+static unibrow::Predicate<SourceCharacter> source_character;
+
+
+static inline bool IsSourceCharacter(uc32 c) {
+  return source_character.get(c);
+}
+
+#ifdef DEBUG
+// Currently only used in an ASSERT.
+static bool IsSpecialClassEscape(uc32 c) {
+  switch (c) {
+    case 'd': case 'D':
+    case 's': case 'S':
+    case 'w': case 'W':
+      return true;
+    default:
+      return false;
+  }
+}
+#endif
+
+
+// In order to know whether an escape is a backreference or not we have to scan
+// the entire regexp and find the number of capturing parentheses.  However we
+// don't want to scan the regexp twice unless it is necessary.  This mini-parser
+// is called when needed.  It can see the difference between capturing and
+// noncapturing parentheses and can skip character classes and backslash-escaped
+// characters.
+void RegExpParser::ScanForCaptures() {
+  int n;
+  while ((n = current()) != kEndMarker) {
+    Advance();
+    switch (n) {
+      case '\\':
+        Advance();
+        break;
+      case '[': {
+        int c;
+        while ((c = current()) != kEndMarker) {
+          Advance();
+          if (c == '\\') {
+            Advance();
+          } else {
+            if (c == ']') break;
+          }
+        }
+        break;
+      }
+      case '(':
+        if (current() != '?') capture_count_++;
+        break;
+    }
+  }
+  is_scanned_for_captures_ = true;
+}
+
+
+bool RegExpParser::ParseBackReferenceIndex(int* index_out) {
+  ASSERT_EQ('\\', current());
+  ASSERT('1' <= Next() && Next() <= '9');
+  // Try to parse a decimal literal that is no greater than the number
+  // of previously encountered left capturing parentheses.
+  // This is a not according the the ECMAScript specification. According to
+  // that, one must accept values up to the total number of left capturing
+  // parentheses in the entire input, even if they are meaningless.
+  if (!is_scanned_for_captures_) {
+    int saved_position = position();
+    ScanForCaptures();
+    Reset(saved_position);
+  }
+  if (capture_count_ == 0) return false;
+  int start = position();
+  int value = Next() - '0';
+  if (value > capture_count_) return false;
+  Advance(2);
+  while (true) {
+    uc32 c = current();
+    if (IsDecimalDigit(c)) {
+      value = 10 * value + (c - '0');
+      if (value > capture_count_) {
+        Reset(start);
+        return false;
+      }
+      Advance();
+    } else {
+      break;
+    }
+  }
+  *index_out = value;
+  return true;
+}
+
+
+// QuantifierPrefix ::
+//   { DecimalDigits }
+//   { DecimalDigits , }
+//   { DecimalDigits , DecimalDigits }
+bool RegExpParser::ParseIntervalQuantifier(int* min_out, int* max_out) {
+  ASSERT_EQ(current(), '{');
+  int start = position();
+  Advance();
+  int min = 0;
+  if (!IsDecimalDigit(current())) {
+    Reset(start);
+    return false;
+  }
+  while (IsDecimalDigit(current())) {
+    min = 10 * min + (current() - '0');
+    Advance();
+  }
+  int max = 0;
+  if (current() == '}') {
+    max = min;
+    Advance();
+  } else if (current() == ',') {
+    Advance();
+    if (current() == '}') {
+      max = RegExpQuantifier::kInfinity;
+      Advance();
+    } else {
+      while (IsDecimalDigit(current())) {
+        max = 10 * max + (current() - '0');
+        Advance();
+      }
+      if (current() != '}') {
+        Reset(start);
+        return false;
+      }
+      Advance();
+    }
+  } else {
+    Reset(start);
+    return false;
+  }
+  *min_out = min;
+  *max_out = max;
+  return true;
+}
+
+
+// Upper and lower case letters differ by one bit.
+STATIC_CHECK(('a' ^ 'A') == 0x20);
+
+uc32 RegExpParser::ParseControlLetterEscape(bool* ok) {
+  if (!has_more()) {
+    ReportError(CStrVector("\\c at end of pattern"), ok);
+    return '\0';
+  }
+  uc32 letter = current() & ~(0x20);  // Collapse upper and lower case letters.
+  if (letter < 'A' || 'Z' < letter) {
+    // Non-spec error-correction: "\c" followed by non-control letter is
+    // interpreted as an IdentityEscape of 'c'.
+    return 'c';
+  }
+  Advance();
+  return letter & 0x1f;  // Remainder modulo 32, per specification.
+}
+
+
+uc32 RegExpParser::ParseOctalLiteral() {
+  ASSERT('0' <= current() && current() <= '7');
+  // For compatibility with some other browsers (not all), we parse
+  // up to three octal digits with a value below 256.
+  uc32 value = current() - '0';
+  Advance();
+  if ('0' <= current() && current() <= '7') {
+    value = value * 8 + current() - '0';
+    Advance();
+    if (value < 32 && '0' <= current() && current() <= '7') {
+      value = value * 8 + current() - '0';
+      Advance();
+    }
+  }
+  return value;
+}
+
+
+bool RegExpParser::ParseHexEscape(int length, uc32 *value) {
+  int start = position();
+  uc32 val = 0;
+  bool done = false;
+  for (int i = 0; !done; i++) {
+    uc32 c = current();
+    int d = HexValue(c);
+    if (d < 0) {
+      Reset(start);
+      return false;
+    }
+    val = val * 16 + d;
+    Advance();
+    if (i == length - 1) {
+      done = true;
+    }
+  }
+  *value = val;
+  return true;
+}
+
+
+uc32 RegExpParser::ParseClassCharacterEscape(bool* ok) {
+  ASSERT(current() == '\\');
+  ASSERT(has_next() && !IsSpecialClassEscape(Next()));
+  Advance();
+  switch (current()) {
+    case 'b':
+      Advance();
+      return '\b';
+    // ControlEscape :: one of
+    //   f n r t v
+    case 'f':
+      Advance();
+      return '\f';
+    case 'n':
+      Advance();
+      return '\n';
+    case 'r':
+      Advance();
+      return '\r';
+    case 't':
+      Advance();
+      return '\t';
+    case 'v':
+      Advance();
+      return '\v';
+    case 'c':
+      return ParseControlLetterEscape(ok);
+    case '0': case '1': case '2': case '3': case '4': case '5':
+    case '6': case '7':
+      // For compatibility, we interpret a decimal escape that isn't
+      // a back reference (and therefore either \0 or not valid according
+      // to the specification) as a 1..3 digit octal character code.
+      return ParseOctalLiteral();
+    case 'x': {
+      Advance();
+      uc32 value;
+      if (ParseHexEscape(2, &value)) {
+        return value;
+      }
+      // If \x is not followed by a two-digit hexadecimal, treat it
+      // as an identity escape.
+      return 'x';
+    }
+    case 'u': {
+      Advance();
+      uc32 value;
+      if (ParseHexEscape(4, &value)) {
+        return value;
+      }
+      // If \u is not followed by a four-digit hexadecimal, treat it
+      // as an identity escape.
+      return 'u';
+    }
+    default: {
+      // Extended identity escape. We accept any character that hasn't
+      // been matched by a more specific case, not just the subset required
+      // by the ECMAScript specification.
+      uc32 result = current();
+      Advance();
+      return result;
+    }
+  }
+  return 0;
+}
+
+
+RegExpTree* RegExpParser::ParseGroup(bool* ok) {
+  ASSERT_EQ(current(), '(');
+  char type = '(';
+  Advance();
+  if (current() == '?') {
+    switch (Next()) {
+      case ':': case '=': case '!':
+        type = Next();
+        Advance(2);
+        break;
+      default:
+        ReportError(CStrVector("Invalid group"), CHECK_OK);
+        break;
+    }
+  } else {
+    if (captures_ == NULL) {
+      captures_ = new ZoneList<RegExpCapture*>(2);
+    }
+    captures_->Add(NULL);
+    if (!is_scanned_for_captures_) capture_count_++;
+  }
+  int capture_index = captures_started();
+  RegExpTree* body = ParseDisjunction(CHECK_OK);
+  if (current() != ')') {
+    ReportError(CStrVector("Unterminated group"), CHECK_OK);
+  }
+  Advance();
+
+  int end_capture_index = captures_started();
+  if (type == '!') {
+    // Captures inside a negative lookahead are never available outside it.
+    for (int i = capture_index; i < end_capture_index; i++) {
+      RegExpCapture* capture = captures_->at(i);
+      ASSERT(capture != NULL);
+      capture->set_available(CAPTURE_PERMANENTLY_UNREACHABLE);
+    }
+  } else {
+    // Captures temporarily unavailable because they are in different
+    // alternatives are all available after the disjunction.
+    for (int i = capture_index; i < end_capture_index; i++) {
+      RegExpCapture* capture = captures_->at(i);
+      ASSERT(capture != NULL);
+      if (capture->available() == CAPTURE_UNREACHABLE) {
+        capture->set_available(CAPTURE_AVAILABLE);
+      }
+    }
+  }
+
+  if (type == '(') {
+    RegExpCapture* capture = new RegExpCapture(body, capture_index);
+    captures_->at(capture_index - 1) = capture;
+    return capture;
+  } else if (type == ':') {
+    return body;
+  } else {
+    ASSERT(type == '=' || type == '!');
+    bool is_positive = (type == '=');
+    return new RegExpLookahead(body, is_positive);
+  }
+}
+
+
+CharacterRange RegExpParser::ParseClassAtom(bool* is_char_class,
+                                            ZoneList<CharacterRange>* ranges,
+                                            bool* ok) {
+  ASSERT_EQ(false, *is_char_class);
+  uc32 first = current();
+  if (first == '\\') {
+    switch (Next()) {
+      case 'w': case 'W': case 'd': case 'D': case 's': case 'S': {
+        *is_char_class = true;
+        uc32 c = Next();
+        CharacterRange::AddClassEscape(c, ranges);
+        Advance(2);
+        return NULL;
+      }
+      default:
+        uc32 c = ParseClassCharacterEscape(CHECK_OK);
+        return CharacterRange::Singleton(c);
+    }
+  } else {
+    Advance();
+    return CharacterRange::Singleton(first);
+  }
+}
+
+
+RegExpTree* RegExpParser::ParseCharacterClass(bool* ok) {
+  static const char* kUnterminated = "Unterminated character class";
+  static const char* kIllegal = "Illegal character class";
+  static const char* kRangeOutOfOrder = "Range out of order in character class";
+
+  ASSERT_EQ(current(), '[');
+  Advance();
+  bool is_negated = false;
+  if (current() == '^') {
+    is_negated = true;
+    Advance();
+  }
+  ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2);
+  while (has_more() && current() != ']') {
+    bool is_char_class = false;
+    CharacterRange first = ParseClassAtom(&is_char_class, ranges, CHECK_OK);
+    if (!is_char_class) {
+      if (current() == '-') {
+        Advance();
+        if (current() == kEndMarker) {
+          // If we reach the end we break out of the loop and let the
+          // following code report an error.
+          break;
+        } else if (current() == ']') {
+          ranges->Add(first);
+          ranges->Add(CharacterRange::Singleton('-'));
+          break;
+        }
+        CharacterRange next =
+            ParseClassAtom(&is_char_class, ranges, CHECK_OK);
+        if (is_char_class) {
+          return ReportError(CStrVector(kIllegal), CHECK_OK);
+        }
+        if (first.from() > next.to()) {
+          return ReportError(CStrVector(kRangeOutOfOrder), CHECK_OK);
+        }
+        ranges->Add(CharacterRange::Range(first.from(), next.to()));
+      } else {
+        ranges->Add(first);
+      }
+    }
+  }
+  if (!has_more()) {
+    return ReportError(CStrVector(kUnterminated), CHECK_OK);
+  }
+  Advance();
+  if (ranges->length() == 0) {
+    ranges->Add(CharacterRange::Range(0, 0xffff));
+    is_negated = !is_negated;
+  }
+  return new RegExpCharacterClass(ranges, is_negated);
+}
+
+
+// ----------------------------------------------------------------------------
 // The Parser interface.
 
 // MakeAST() is just a wrapper for the corresponding Parser calls
@@ -3211,6 +4290,27 @@ ScriptDataImpl* PreParse(unibrow::CharacterStream* stream,
 }
 
 
+bool ParseRegExp(FlatStringReader* input, RegExpParseResult* result) {
+  ASSERT(result != NULL);
+  // Get multiline flag somehow
+  RegExpParser parser(input, &result->error, false);
+  bool ok = true;
+  result->tree = parser.ParsePattern(&ok);
+  if (!ok) {
+    ASSERT(result->tree == NULL);
+    ASSERT(!result->error.is_null());
+  } else {
+    ASSERT(result->tree != NULL);
+    ASSERT(result->error.is_null());
+  }
+  if (ok) {
+    result->has_character_escapes = parser.HasCharacterEscapes();
+    result->capture_count = parser.captures_started();
+  }
+  return ok;
+}
+
+
 FunctionLiteral* MakeAST(bool compile_in_global_context,
                          Handle<Script> script,
                          v8::Extension* extension,
index d331d73..b6de9e5 100644 (file)
@@ -145,6 +145,9 @@ ScriptDataImpl* PreParse(unibrow::CharacterStream* stream,
                          v8::Extension* extension);
 
 
+bool ParseRegExp(FlatStringReader* input, RegExpParseResult* result);
+
+
 // Support for doing lazy compilation. The script is the script containing full
 // source of the script where the function is declared. The start_position and
 // end_position specifies the part of the script source which has the source
diff --git a/src/regexp-macro-assembler-ia32.cc b/src/regexp-macro-assembler-ia32.cc
new file mode 100644 (file)
index 0000000..4fc725e
--- /dev/null
@@ -0,0 +1,605 @@
+// Copyright 2008 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 <string.h>
+#include "v8.h"
+#include "log.h"
+#include "ast.h"
+#include "macro-assembler.h"
+#include "regexp-macro-assembler-ia32.h"
+
+namespace v8 { namespace internal {
+/*
+ * This assembler uses the following register assignment convention
+ * - edx : current character, or kEndOfInput if current position is not
+ *         inside string. The kEndOfInput value is greater than 0xffff,
+ *         so any tests that don't check whether the current position
+ *         is inside the correct range should retain bits above the
+ *         15th in their computations, and fail if the value is too
+ *         great.
+ * - edi : current position in input, as negative offset from end of string.
+ * - esi : end of input (points to byte after last character in input).
+ * - ebp : points to the location above the registers on the stack,
+ *         as if by the "enter <register_count>" opcode.
+ * - esp : points to tip of backtracking stack.
+ *
+ * The registers eax, ebx and ecx are free to use for computations.
+ *
+ * Each call to a public method should retain this convention.
+ * The stack will have the following structure:
+ *       - int* capture_array (int[num_saved_registers_], for output).
+ *       - end of input       (index of end of string, relative to *string_base)
+ *       - start of input     (index of first character in string, relative
+ *                            to *string_base)
+ *       - void** string_base (location of a handle containing the string)
+ *       - return address
+ *       - backup of esi
+ *       - backup of edi
+ * ebp-> - old ebp
+ *       - register 0  ebp[-4]
+ *       - register 1  ebp[-8]
+ *       - ...
+ *
+ * The data before ebp must be placed there by the calling code, e.g.,
+ * by calling the code as cast to:
+ * bool (*match)(String** string_base,
+ *               int start_offset,
+ *               int end_offset,
+ *               int* capture_output_array)
+ */
+
+#define __ masm_->
+
+RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(
+    Mode mode,
+    int registers_to_save,
+    bool ignore_case)
+  : masm_(new MacroAssembler(NULL, kRegExpCodeSize)),
+    constants_(kRegExpConstantsSize),
+    mode_(mode),
+    num_registers_(registers_to_save),
+    num_saved_registers_(registers_to_save),
+    ignore_case_(ignore_case),
+    entry_label_(),
+    start_label_(),
+    success_label_(),
+    exit_label_(),
+    self_(Heap::undefined_value()) {
+  __ jmp(&entry_label_);   // We'll write the entry code later.
+  __ bind(&start_label_);  // And then continue from here.
+}
+
+
+RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() {
+  delete masm_;
+  // Unuse labels in case we throw away the assembler without calling GetCode.
+  entry_label_.Unuse();
+  start_label_.Unuse();
+  success_label_.Unuse();
+  exit_label_.Unuse();
+}
+
+
+void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) {
+  ASSERT(by > 0);
+  Label inside_string;
+  __ add(Operand(edi), Immediate(by * char_size()));
+  __ j(below, &inside_string);
+  Backtrack();
+
+  __ bind(&inside_string);
+}
+
+
+void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) {
+  ASSERT(reg >= 0);
+  ASSERT(reg < num_registers_);
+  __ add(register_location(reg), Immediate(by));
+}
+
+
+void RegExpMacroAssemblerIA32::Backtrack() {
+  __ pop(ecx);
+  __ add(Operand(ecx), Immediate(self_));
+  __ jmp(Operand(ecx));
+}
+
+
+void RegExpMacroAssemblerIA32::Bind(Label* label) {
+  __ bind(label);
+}
+
+void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start,
+                                           Label* bitmap,
+                                           Label* on_zero) {
+  ReadCurrentChar(eax);
+  __ sub(Operand(eax), Immediate(start));
+  __ cmp(eax, 64);  // FIXME: 64 = length_of_bitmap_in_bits.
+  BranchOrBacktrack(greater_equal, on_zero);
+  __ mov(ebx, eax);
+  __ shr(ebx, 3);
+  // TODO(lrn): Where is the bitmap stored? Pass the bitmap as argument instead.
+  // __ mov(ecx, position_of_bitmap);
+  __ movzx_b(ebx, Operand(ecx, ebx, times_1, 0));
+  __ and_(eax, (1<<3)-1);
+  __ bt(Operand(ebx), eax);
+  __ j(carry, on_zero);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCharacter(uc16 c, Label* on_equal) {
+  __ cmp(edx, c);
+  BranchOrBacktrack(equal, on_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
+  __ cmp(edx, limit);
+  BranchOrBacktrack(greater, on_greater);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) {
+  __ cmp(edx, limit);
+  BranchOrBacktrack(less, on_less);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
+                                               int cp_offset,
+                                               Label* on_failure) {
+  int byte_length = str.length() * char_size();
+  int start_offset = cp_offset * char_size();
+  __ mov(ebx, edi);
+  __ add(Operand(ebx), Immediate(start_offset + byte_length));
+  BranchOrBacktrack(greater_equal, on_failure);
+
+  ArraySlice constant_buffer = constants_.GetBuffer(str.length(), char_size());
+  for (int i = 0; i < str.length(); i++) {
+    if (mode_ == ASCII) {
+      constant_buffer.at<char>(i) = static_cast<char>(str[i]);
+    } else {
+      memcpy(constant_buffer.location<void>(),
+             str.start(),
+             str.length() * sizeof(uc16));
+    }
+  }
+
+  __ mov(eax, edi);
+  __ mov(ebx, esi);
+  __ lea(edi, Operand(esi, edi, times_1, start_offset));
+  LoadConstantBufferAddress(esi, &constant_buffer);
+  __ mov(ecx, str.length());
+  if (mode_ == ASCII) {
+    __ rep_cmpsb();
+  } else {
+    ASSERT(mode_ == UC16);
+    __ rep_cmpsw();
+  }
+  __ mov(esi, ebx);
+  __ mov(edi, eax);
+  BranchOrBacktrack(not_equal, on_failure);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCurrentPosition(int register_index,
+                                                    Label* on_equal) {
+  __ cmp(edi, register_location(register_index));
+  BranchOrBacktrack(equal, on_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotBackReference(
+    int start_reg, Label* on_no_match) {
+  if (ignore_case_) {
+    UNIMPLEMENTED();
+  }
+  Label fallthrough;
+  __ mov(eax, register_location(start_reg));
+  __ mov(ecx, register_location(start_reg + 1));
+  __ sub(ecx, Operand(eax));  // Length to check.
+  __ j(equal, &fallthrough);  // Covers the case where it's not bound (-1,-1).
+  __ mov(ebx, Operand(edi));
+  __ push(esi);
+  __ add(edi, Operand(esi));
+  __ add(esi, Operand(eax));
+  if (mode_ == ASCII) {
+    __ rep_cmpsb();
+  } else {
+    __ rep_cmpsw();
+  }
+  __ pop(esi);
+  __ mov(edi, Operand(ebx));
+  BranchOrBacktrack(not_equal, on_no_match);
+  __ bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotCharacter(uc16 c, Label* on_not_equal) {
+  __ cmp(edx, c);
+  BranchOrBacktrack(not_equal, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotCharacterAfterOr(uc16 c,
+                                                        uc16 mask,
+                                                        Label* on_not_equal) {
+  __ mov(eax, Operand(edx));
+  __ or_(eax, mask);
+  __ cmp(eax, c);
+  BranchOrBacktrack(not_equal, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusOr(
+    uc16 c,
+    uc16 mask,
+    Label* on_not_equal) {
+  __ lea(eax, Operand(edx, -mask));
+  __ or_(eax, mask);
+  __ cmp(eax, c);
+  BranchOrBacktrack(not_equal, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::DispatchHalfNibbleMap(
+    uc16 start,
+    Label* half_nibble_map,
+    const Vector<Label*>& destinations) {
+  ReadCurrentChar(eax);
+  __ sub(Operand(eax), Immediate(start));
+
+  __ mov(ecx, eax);
+  __ shr(eax, 2);
+  // FIXME: ecx must hold address of map
+  __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
+  __ and_(ecx, 0x03);
+  __ add(ecx, Operand(ecx));
+  __ shr(eax);  // Shift right cl times
+
+  Label second_bit_set, case_3, case_1;
+  __ test(eax, Immediate(0x02));
+  __ j(not_zero, &second_bit_set);
+  __ test(eax, Immediate(0x01));
+  __ j(not_zero, &case_1);
+  // Case 0:
+  __ jmp(destinations[0]);
+  __ bind(&case_1);
+  // Case 1:
+  __ jmp(destinations[1]);
+  __ bind(&second_bit_set);
+  __ test(eax, Immediate(0x01));
+  __ j(not_zero, &case_3);
+  // Case 2
+  __ jmp(destinations[2]);
+  __ bind(&case_3);
+  // Case 3:
+  __ jmp(destinations[3]);
+}
+
+
+void RegExpMacroAssemblerIA32::DispatchByteMap(
+    uc16 start,
+    Label* byte_map,
+    const Vector<Label*>& destinations) {
+  Label fallthrough;
+  ReadCurrentChar(eax);
+  __ sub(Operand(eax), Immediate(start));
+  __ cmp(eax, 64);  // FIXME: 64 = size of map. Found somehow??
+  __ j(greater_equal, &fallthrough);
+  // FIXME: ecx must hold address of map
+  __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
+  // jump table: jump to destinations[eax];
+
+  __ bind(&fallthrough);
+}
+
+
+
+void RegExpMacroAssemblerIA32::DispatchHighByteMap(
+    byte start,
+    Label* byte_map,
+    const Vector<Label*>& destinations) {
+  Label fallthrough;
+  ReadCurrentChar(eax);
+  __ shr(eax, 8);
+  __ sub(Operand(eax), Immediate(start));
+  __ cmp(eax, destinations.length() - start);
+  __ j(greater_equal, &fallthrough);
+
+  // TODO(lrn) jumptable: jump to destinations[eax]
+  __ bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerIA32::EmitOrLink(Label* label) {
+  UNREACHABLE();  // Has no use.
+}
+
+
+void RegExpMacroAssemblerIA32::Fail() {
+  __ mov(eax, 0);
+  __ jmp(&exit_label_);
+}
+
+
+Handle<Object> RegExpMacroAssemblerIA32::GetCode() {
+  // Finalize code - write the entry point code now we know how many
+  // registers we need.
+
+  // Entry code:
+  __ bind(&entry_label_);
+  __ push(esi);
+  __ push(edi);
+  __ enter(Immediate(num_registers_ * sizeof(uint32_t)));
+  __ mov(esi, Operand(ebp, kInputEndOffset));
+  __ mov(edi, Operand(ebp, kInputStartOffset));
+  __ sub(edi, Operand(esi));
+  __ mov(edx, Operand(ebp, kInputBuffer));
+  __ mov(edx, Operand(edx, 0));
+  __ add(esi, Operand(edx));
+  __ jmp(&start_label_);
+
+  // Exit code:
+  __ bind(&success_label_);
+  __ mov(ebx, Operand(ebp, kRegisterOutput));
+  __ mov(ecx, Operand(ebp, kInputEndOffset));
+  __ sub(ecx, Operand(ebp, kInputStartOffset));
+  for (int i = 0; i < num_saved_registers_; i++) {
+    __ mov(eax, register_location(i));
+    __ sub(eax, Operand(ecx));  // Convert to index from start, not end.
+    __ mov(Operand(ebx, i * sizeof(int32_t)), eax);
+  }
+  // copy captures to output
+  __ mov(eax, Immediate(1));
+
+  __ bind(&exit_label_);
+  __ leave();
+  __ pop(edi);
+  __ pop(esi);
+  __ ret(0);
+
+  CodeDesc code_desc;
+  masm_->GetCode(&code_desc);
+  Handle<Code> code = Factory::NewCode(code_desc,
+                                       NULL,
+                                       Code::ComputeFlags(Code::REGEXP),
+                                       self_);
+  LOG(CodeCreateEvent("RegExp", *code, "(Compiled RegExp)"));
+  return Handle<Object>::cast(code);
+}
+
+
+void RegExpMacroAssemblerIA32::GoTo(Label* to) {
+  __ jmp(to);
+}
+
+
+
+void RegExpMacroAssemblerIA32::IfRegisterGE(int reg,
+                                            int comparand,
+                                            Label* if_ge) {
+  __ cmp(register_location(reg), Immediate(comparand));
+  BranchOrBacktrack(greater_equal, if_ge);
+}
+
+
+
+void RegExpMacroAssemblerIA32::IfRegisterLT(int reg,
+                                            int comparand,
+                                            Label* if_lt) {
+  __ cmp(register_location(reg), Immediate(comparand));
+  BranchOrBacktrack(less, if_lt);
+}
+
+
+
+RegExpMacroAssembler::IrregexpImplementation
+    RegExpMacroAssemblerIA32::Implementation() {
+  return kIA32Implementation;
+}
+
+
+
+void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
+                                                    Label* on_end_of_input) {
+  ASSERT(cp_offset >= 0);
+  ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
+  __ cmp(edi, -cp_offset);
+  BranchOrBacktrack(less_equal, on_end_of_input);
+  ReadChar(edx, cp_offset);
+}
+
+
+void RegExpMacroAssemblerIA32::PopCurrentPosition() {
+  __ pop(edi);
+}
+
+
+void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
+  RecordRegister(register_index);
+  __ pop(register_location(register_index));
+}
+
+
+void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) {
+  // Check for preemption first.
+  Label no_preempt;
+  Label retry_preempt;
+  // Check for preemption.
+  ExternalReference stack_limit =
+      ExternalReference::address_of_stack_guard_limit();
+  __ cmp(esp, Operand::StaticVariable(stack_limit));
+  __ j(above, &no_preempt);
+
+  __ push(edi);  // Current position.
+  __ push(edx);  // Current character.
+  // Restore original edi, esi.
+  __ mov(edi, Operand(ebp, kBackup_edi));
+  __ mov(esi, Operand(ebp, kBackup_esi));
+
+  __ bind(&retry_preempt);
+  // simulate stack for Runtime call.
+  __ push(Immediate(0));  // Dummy receiver
+  __ CallRuntime(Runtime::kStackGuard, 0);
+  __ cmp(esp, Operand::StaticVariable(stack_limit));
+  __ j(below_equal, &retry_preempt);
+
+  __ pop(edx);
+  __ pop(edi);
+  __ mov(esi, Operand(ebp, kInputBuffer));
+  __ mov(esi, Operand(esi, 0));
+  __ add(esi, Operand(ebp, kInputEndOffset));
+
+  __ bind(&no_preempt);
+
+  Label cont;
+  __ push(label, RelocInfo::NONE);
+}
+
+
+void RegExpMacroAssemblerIA32::PushCurrentPosition() {
+  __ push(edi);
+}
+
+
+void RegExpMacroAssemblerIA32::PushRegister(int register_index) {
+  __ push(register_location(register_index));
+}
+
+
+void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) {
+  __ mov(edi, register_location(reg));
+}
+
+
+void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) {
+  __ mov(esp, register_location(reg));
+}
+
+
+void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) {
+  RecordRegister(register_index);
+  __ mov(register_location(register_index), Immediate(to));
+}
+
+
+void RegExpMacroAssemblerIA32::Succeed() {
+  __ jmp(&success_label_);
+}
+
+
+void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(
+    int register_index) {
+  __ mov(register_location(register_index), edi);
+}
+
+void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
+  __ mov(register_location(reg), esp);
+}
+
+
+// Private methods:
+
+Operand RegExpMacroAssemblerIA32::register_location(
+    int register_index) {
+  ASSERT(register_index < (1<<30));
+  return Operand(ebp, -((register_index + 1) * sizeof(uint32_t)));
+}
+
+
+size_t RegExpMacroAssemblerIA32::char_size() {
+  return static_cast<size_t>(mode_);
+}
+
+
+void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
+                                                 Label* to) {
+  if (condition < 0) {  // No condition
+    if (to == NULL) {
+      Backtrack();
+      return;
+    }
+    __ jmp(to);
+    return;
+  } else if (to == NULL) {
+    Label skip;
+    __ j(NegateCondition(condition), &skip);
+    Backtrack();
+    __ bind(&skip);
+    return;
+  }
+  __ j(condition, to);
+}
+
+
+void RegExpMacroAssemblerIA32::Canonicalize(Register reg) {
+  if (mode_ == ASCII) {
+    Label end;
+    __ cmp(Operand(reg), Immediate('a'));
+    __ j(below, &end);
+    __ cmp(Operand(reg), Immediate('z'));
+    __ j(above, &end);
+    __ sub(Operand(reg), Immediate('a' - 'A'));
+    __ bind(&end);
+    return;
+  }
+  ASSERT(mode_ == UC16);
+  // TODO(lrn): Use some tables.
+}
+
+
+void RegExpMacroAssemblerIA32::RecordRegister(int register_index) {
+  if (register_index >= num_registers_) {
+    num_registers_ = register_index + 1;
+  }
+}
+
+
+void RegExpMacroAssemblerIA32::ReadChar(Register destination, int offset) {
+  if (mode_ == ASCII) {
+    __ movzx_b(destination, Operand(esi, edi, times_1, offset));
+    return;
+  }
+  ASSERT(mode_ == UC16);
+  __ movzx_w(destination, Operand(esi, edi, times_1, offset * 2));
+}
+
+
+void RegExpMacroAssemblerIA32::ReadCurrentChar(Register destination) {
+  __ mov(destination, edx);
+}
+
+
+void RegExpMacroAssemblerIA32::LoadConstantBufferAddress(Register reg,
+                                                         ArraySlice* buffer) {
+  __ mov(reg, buffer->array());
+  __ add(Operand(reg), Immediate(buffer->base_offset()));
+}
+
+#undef __
+}}
diff --git a/src/regexp-macro-assembler-ia32.h b/src/regexp-macro-assembler-ia32.h
new file mode 100644 (file)
index 0000000..a855947
--- /dev/null
@@ -0,0 +1,162 @@
+// Copyright 2008 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 REGEXP_MACRO_ASSEMBLER_IA32_H_
+#define REGEXP_MACRO_ASSEMBLER_IA32_H_
+
+#if !(defined __arm__ || defined __thumb__ || defined ARM)
+
+#include "regexp-macro-assembler.h"
+#include "macro-assembler-ia32.h"
+
+namespace v8 { namespace internal {
+
+class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
+ public:
+  enum Mode {ASCII = 1, UC16 = 2};
+  RegExpMacroAssemblerIA32(Mode mode, int registers_to_save, bool ignore_case);
+  virtual ~RegExpMacroAssemblerIA32();
+  virtual void AdvanceCurrentPosition(int by);
+  virtual void AdvanceRegister(int reg, int by);
+  virtual void Backtrack();
+  virtual void Bind(Label* label);
+  virtual void CheckBitmap(uc16 start, Label* bitmap, Label* on_zero);
+  virtual void CheckCharacter(uc16 c, Label* on_equal);
+  virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
+  virtual void CheckCharacterLT(uc16 limit, Label* on_less);
+  virtual void CheckCharacters(Vector<const uc16> str,
+                               int cp_offset,
+                               Label* on_failure);
+  virtual void CheckCurrentPosition(int register_index, Label* on_equal);
+  virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
+  virtual void CheckNotCharacter(uc16 c, Label* on_not_equal);
+  virtual void CheckNotCharacterAfterOr(uc16 c, uc16 mask, Label* on_not_equal);
+  virtual void CheckNotCharacterAfterMinusOr(uc16 c,
+                                             uc16 mask,
+                                             Label* on_not_equal);
+  virtual void DispatchByteMap(uc16 start,
+                               Label* byte_map,
+                               const Vector<Label*>& destinations);
+  virtual void DispatchHalfNibbleMap(uc16 start,
+                                     Label* half_nibble_map,
+                                     const Vector<Label*>& destinations);
+  virtual void DispatchHighByteMap(byte start,
+                                   Label* byte_map,
+                                   const Vector<Label*>& destinations);
+  virtual void EmitOrLink(Label* label);
+  virtual void Fail();
+  virtual Handle<Object> GetCode();
+  virtual void GoTo(Label* label);
+  virtual void IfRegisterGE(int reg, int comparand, Label* if_ge);
+  virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
+  virtual IrregexpImplementation Implementation();
+  virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input);
+  virtual void PopCurrentPosition();
+  virtual void PopRegister(int register_index);
+  virtual void PushBacktrack(Label* label);
+  virtual void PushCurrentPosition();
+  virtual void PushRegister(int register_index);
+  virtual void ReadCurrentPositionFromRegister(int reg);
+  virtual void ReadStackPointerFromRegister(int reg);
+  virtual void SetRegister(int register_index, int to);
+  virtual void Succeed();
+  virtual void WriteCurrentPositionToRegister(int reg);
+  virtual void WriteStackPointerToRegister(int reg);
+ private:
+  // Offsets from ebp of arguments to function.
+  static const int kBackup_edi = 1 * sizeof(uint32_t);
+  static const int kBackup_esi= 2 * sizeof(uint32_t);
+  static const int kInputBuffer = 4 * sizeof(uint32_t);
+  static const int kInputStartOffset = 5 * sizeof(uint32_t);
+  static const int kInputEndOffset = 6 * sizeof(uint32_t);
+  static const int kRegisterOutput = 7 * sizeof(uint32_t);
+
+  // The ebp-relative location of a regexp register.
+  Operand register_location(int register_index);
+
+  // Whether to implement case-insensitive matching.
+  bool ignore_case();
+
+  // Byte size of chars in the string to match (decided by the Mode argument)
+  size_t char_size();
+
+  // Records that a register is used. At the end, we need the number of
+  // registers used.
+  void RecordRegister(int register_index);
+
+  // Equivalent to a conditional branch to the label, unless the label
+  // is NULL, in which case it is a conditional Backtrack.
+  void BranchOrBacktrack(Condition condition, Label* to);
+
+  // Generate code to perform case-canonicalization on the register.
+  void Canonicalize(Register register);
+
+  // Read a character from input at the given offset from the current
+  // position.
+  void ReadChar(Register destination, int offset);
+
+  // Load the address of a "constant buffer" (a slice of a byte array)
+  // into a register. The address is computed from the ByteArray* address
+  // and an offset. Uses no extra registers.
+  void LoadConstantBufferAddress(Register reg, ArraySlice* buffer);
+
+  // Read the current character into the destination register.
+  void ReadCurrentChar(Register destination);
+
+  // Initial size of code buffer.
+  static const size_t kRegExpCodeSize = 1024;
+  // Initial size of constant buffers allocated during compilation.
+  static const int kRegExpConstantsSize = 256;
+  // Only unroll loops up to this length.
+  static const int kMaxInlineStringTests = 8;
+  // Special "character" marking end of input.
+  static const uint32_t kEndOfInput = ~0;
+
+  MacroAssembler* masm_;
+  ByteArrayProvider constants_;
+  // Which mode to generate code for (ASCII or UTF16).
+  Mode mode_;
+  // One greater than maximal register index actually used.
+  int num_registers_;
+  // Number of registers to output at the end (the saved registers
+  // are always 0..num_saved_registers_-1)
+  int num_saved_registers_;
+  // Whether to generate code that is case-insensitive. Only relevant for
+  // back-references.
+  bool ignore_case_;
+  Label entry_label_;
+  Label start_label_;
+  Label success_label_;
+  Label exit_label_;
+  // Handle used to represent the generated code object itself.
+  Handle<Object> self_;
+};
+}}
+
+#endif  // !ARM
+
+#endif /* REGEXP_MACRO_ASSEMBLER_IA32_H_ */
diff --git a/src/regexp-macro-assembler-irregexp.cc b/src/regexp-macro-assembler-irregexp.cc
new file mode 100644 (file)
index 0000000..7e98c4d
--- /dev/null
@@ -0,0 +1,266 @@
+// Copyright 2008 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 "v8.h"
+#include "ast.h"
+#include "bytecodes-irregexp.h"
+#include "assembler-irregexp.h"
+#include "assembler-irregexp-inl.h"
+#include "regexp-macro-assembler.h"
+#include "regexp-macro-assembler-irregexp.h"
+
+
+namespace v8 { namespace internal {
+
+
+RegExpMacroAssemblerIrregexp::~RegExpMacroAssemblerIrregexp() {
+}
+
+
+RegExpMacroAssemblerIrregexp::IrregexpImplementation
+RegExpMacroAssemblerIrregexp::Implementation() {
+  return kBytecodeImplementation;
+}
+
+
+void RegExpMacroAssemblerIrregexp::Bind(Label* l) {
+  assembler_->Bind(l);
+}
+
+
+void RegExpMacroAssemblerIrregexp::EmitOrLink(Label* l) {
+  assembler_->EmitOrLink(l);
+}
+
+
+void RegExpMacroAssemblerIrregexp::PopRegister(int register_index) {
+  assembler_->PopRegister(register_index);
+}
+
+
+void RegExpMacroAssemblerIrregexp::PushRegister(int register_index) {
+  assembler_->PushRegister(register_index);
+}
+
+
+void RegExpMacroAssemblerIrregexp::WriteCurrentPositionToRegister(
+    int register_index) {
+  assembler_->WriteCurrentPositionToRegister(register_index);
+}
+
+
+void RegExpMacroAssemblerIrregexp::ReadCurrentPositionFromRegister(
+    int register_index) {
+  assembler_->ReadCurrentPositionFromRegister(register_index);
+}
+
+
+void RegExpMacroAssemblerIrregexp::WriteStackPointerToRegister(
+    int register_index) {
+  assembler_->WriteStackPointerToRegister(register_index);
+}
+
+
+void RegExpMacroAssemblerIrregexp::ReadStackPointerFromRegister(
+    int register_index) {
+  assembler_->ReadStackPointerFromRegister(register_index);
+}
+
+
+void RegExpMacroAssemblerIrregexp::SetRegister(int register_index, int to) {
+  assembler_->SetRegister(register_index, to);
+}
+
+
+void RegExpMacroAssemblerIrregexp::AdvanceRegister(int register_index, int by) {
+  assembler_->AdvanceRegister(register_index, by);
+}
+
+
+void RegExpMacroAssemblerIrregexp::PopCurrentPosition() {
+  assembler_->PopCurrentPosition();
+}
+
+
+void RegExpMacroAssemblerIrregexp::PushCurrentPosition() {
+  assembler_->PushCurrentPosition();
+}
+
+
+void RegExpMacroAssemblerIrregexp::Backtrack() {
+  assembler_->PopBacktrack();
+}
+
+
+void RegExpMacroAssemblerIrregexp::GoTo(Label* l) {
+  assembler_->GoTo(l);
+}
+
+
+void RegExpMacroAssemblerIrregexp::PushBacktrack(Label* l) {
+  assembler_->PushBacktrack(l);
+}
+
+
+void RegExpMacroAssemblerIrregexp::Succeed() {
+  assembler_->Succeed();
+}
+
+
+void RegExpMacroAssemblerIrregexp::Fail() {
+  assembler_->Fail();
+}
+
+
+void RegExpMacroAssemblerIrregexp::AdvanceCurrentPosition(int by) {
+  assembler_->AdvanceCP(by);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckCurrentPosition(
+  int register_index,
+  Label* on_equal) {
+  // TODO(erikcorry): Implement.
+  UNREACHABLE();
+}
+
+
+void RegExpMacroAssemblerIrregexp::LoadCurrentCharacter(int cp_offset,
+                                                        Label* on_failure) {
+  assembler_->LoadCurrentChar(cp_offset, on_failure);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckCharacterLT(uc16 limit,
+                                                    Label* on_less) {
+  assembler_->CheckCharacterLT(limit, on_less);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckCharacterGT(uc16 limit,
+                                                    Label* on_greater) {
+  assembler_->CheckCharacterGT(limit, on_greater);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckCharacter(uc16 c, Label* on_equal) {
+  assembler_->CheckCharacter(c, on_equal);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckNotCharacter(uc16 c,
+                                                     Label* on_not_equal) {
+  assembler_->CheckNotCharacter(c, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckNotCharacterAfterOr(uc16 c,
+                                                        uc16 mask,
+                                                        Label* on_not_equal) {
+  assembler_->OrThenCheckNotCharacter(c, mask, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckNotCharacterAfterMinusOr(
+    uc16 c,
+    uc16 mask,
+    Label* on_not_equal) {
+  assembler_->MinusOrThenCheckNotCharacter(c, mask, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckNotBackReference(int start_reg,
+                                                     Label* on_not_equal) {
+  assembler_->CheckNotBackReference(start_reg, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckBitmap(uc16 start,
+                                           Label* bitmap,
+                                           Label* on_zero) {
+  assembler_->LookupMap1(start, bitmap, on_zero);
+}
+
+
+void RegExpMacroAssemblerIrregexp::DispatchHalfNibbleMap(
+    uc16 start,
+    Label* half_nibble_map,
+    const Vector<Label*>& table) {
+  assembler_->LookupMap2(start, half_nibble_map, table);
+}
+
+
+void RegExpMacroAssemblerIrregexp::DispatchByteMap(
+    uc16 start,
+    Label* byte_map,
+    const Vector<Label*>& table) {
+  assembler_->LookupMap8(start, byte_map, table);
+}
+
+
+void RegExpMacroAssemblerIrregexp::DispatchHighByteMap(
+    byte start,
+    Label* byte_map,
+    const Vector<Label*>& table) {
+  assembler_->LookupHighMap8(start, byte_map, table);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckCharacters(
+  Vector<const uc16> str,
+  int cp_offset,
+  Label* on_failure) {
+  for (int i = str.length() - 1; i >= 0; i--) {
+    assembler_->LoadCurrentChar(cp_offset + i, on_failure);
+    assembler_->CheckNotCharacter(str[i], on_failure);
+  }
+}
+
+
+void RegExpMacroAssemblerIrregexp::IfRegisterLT(int register_index,
+                                                int comparand,
+                                                Label* if_less_than) {
+  ASSERT(comparand >= 0 && comparand <= 65535);
+  assembler_->CheckRegisterLT(register_index, comparand, if_less_than);
+}
+
+
+void RegExpMacroAssemblerIrregexp::IfRegisterGE(int register_index,
+                                                int comparand,
+                                                Label* if_greater_or_equal) {
+  ASSERT(comparand >= 0 && comparand <= 65535);
+  assembler_->CheckRegisterGE(register_index, comparand, if_greater_or_equal);
+}
+
+
+Handle<Object> RegExpMacroAssemblerIrregexp::GetCode() {
+  Handle<ByteArray> array = Factory::NewByteArray(assembler_->length());
+  assembler_->Copy(array->GetDataStartAddress());
+  return array;
+}
+
+} }  // namespace v8::internal
diff --git a/src/regexp-macro-assembler-irregexp.h b/src/regexp-macro-assembler-irregexp.h
new file mode 100644 (file)
index 0000000..fc4879e
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2008 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_MACRO_ASSEMBLER_IRREGEXP_H_
+#define V8_REGEXP_MACRO_ASSEMBLER_IRREGEXP_H_
+
+namespace v8 { namespace internal {
+
+
+class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
+ public:
+  explicit RegExpMacroAssemblerIrregexp(IrregexpAssembler* assembler)
+    : assembler_(assembler) {
+  }
+  virtual ~RegExpMacroAssemblerIrregexp();
+  virtual void Bind(Label* label);
+  virtual void EmitOrLink(Label* label);
+  virtual void AdvanceCurrentPosition(int by);  // Signed cp change.
+  virtual void PopCurrentPosition();
+  virtual void PushCurrentPosition();
+  virtual void Backtrack();
+  virtual void GoTo(Label* label);
+  virtual void PushBacktrack(Label* label);
+  virtual void Succeed();
+  virtual void Fail();
+  virtual void PopRegister(int register_index);
+  virtual void PushRegister(int register_index);
+  virtual void AdvanceRegister(int reg, int by);  // r[reg] += by.
+  virtual void SetRegister(int register_index, int to);
+  virtual void WriteCurrentPositionToRegister(int reg);
+  virtual void ReadCurrentPositionFromRegister(int reg);
+  virtual void WriteStackPointerToRegister(int reg);
+  virtual void ReadStackPointerFromRegister(int reg);
+  virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input);
+  virtual void CheckCharacterLT(uc16 limit, Label* on_less);
+  virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
+  virtual void CheckCharacter(uc16 c, Label* on_equal);
+  virtual void CheckNotCharacter(uc16 c, Label* on_not_equal);
+  virtual void CheckNotCharacterAfterOr(uc16 c, uc16 mask, Label* on_not_equal);
+  virtual void CheckNotCharacterAfterMinusOr(uc16 c,
+                                             uc16 mask,
+                                             Label* on_not_equal);
+  virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
+  virtual void CheckCharacters(Vector<const uc16> str,
+                               int cp_offset,
+                               Label* on_failure);
+  virtual void CheckCurrentPosition(int register_index, Label* on_equal);
+  virtual void CheckBitmap(uc16 start, Label* bitmap, Label* on_zero);
+  virtual void DispatchHalfNibbleMap(uc16 start,
+                                     Label* half_nibble_map,
+                                     const Vector<Label*>& destinations);
+  virtual void DispatchByteMap(uc16 start,
+                               Label* byte_map,
+                               const Vector<Label*>& destinations);
+  virtual void DispatchHighByteMap(byte start,
+                                   Label* byte_map,
+                                   const Vector<Label*>& destinations);
+  virtual void IfRegisterLT(int register_index, int comparand, Label* if_lt);
+  virtual void IfRegisterGE(int register_index, int comparand, Label* if_ge);
+
+  virtual IrregexpImplementation Implementation();
+  virtual Handle<Object> GetCode();
+ private:
+  IrregexpAssembler* assembler_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_REGEXP_MACRO_ASSEMBLER_IRREGEXP_H_
diff --git a/src/regexp-macro-assembler.cc b/src/regexp-macro-assembler.cc
new file mode 100644 (file)
index 0000000..0f9876d
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2008 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 <string.h>
+#include "v8.h"
+#include "ast.h"
+#include "assembler.h"
+#include "regexp-macro-assembler.h"
+
+namespace v8 { namespace internal {
+
+RegExpMacroAssembler::RegExpMacroAssembler() {
+}
+
+
+RegExpMacroAssembler::~RegExpMacroAssembler() {
+}
+
+
+ByteArrayProvider::ByteArrayProvider(unsigned int initial_size)
+  : byte_array_size_(initial_size),
+    current_byte_array_(),
+    current_byte_array_free_offset_(initial_size) {}
+
+
+ArraySlice ByteArrayProvider::GetBuffer(unsigned int size,
+                                        unsigned int elem_size) {
+  ASSERT(size > 0);
+  size_t byte_size = size * elem_size;
+  int free_offset = current_byte_array_free_offset_;
+  // align elements
+  free_offset += elem_size - 1;
+  free_offset = free_offset - (free_offset % elem_size);
+
+  if (free_offset + byte_size > byte_array_size_) {
+    if (byte_size > (byte_array_size_ / 2)) {
+      Handle<ByteArray> solo_buffer(Factory::NewByteArray(byte_size, TENURED));
+      return ArraySlice(solo_buffer, 0);
+    }
+    current_byte_array_ = Factory::NewByteArray(byte_array_size_, TENURED);
+    free_offset = 0;
+  }
+  current_byte_array_free_offset_ = free_offset + size;
+  return ArraySlice(current_byte_array_, free_offset);
+}
+
+template <typename T>
+ArraySlice ByteArrayProvider::GetBuffer(Vector<T> values) {
+  ArraySlice slice = GetBuffer(values.length(), sizeof(T));
+  memcpy(slice.location<void>(), values.start(), values.length() * sizeof(T));
+  return slice;
+}
+} }
diff --git a/src/regexp-macro-assembler.h b/src/regexp-macro-assembler.h
new file mode 100644 (file)
index 0000000..b2f18fe
--- /dev/null
@@ -0,0 +1,181 @@
+// Copyright 2008 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_MACRO_ASSEMBLER_H_
+#define V8_REGEXP_MACRO_ASSEMBLER_H_
+
+namespace v8 { namespace internal {
+
+
+struct DisjunctDecisionRow {
+  RegExpCharacterClass cc;
+  Label* on_match;
+};
+
+
+class RegExpMacroAssembler {
+ public:
+  enum IrregexpImplementation {
+    kIA32Implementation,
+    kARMImplementation,
+    kBytecodeImplementation};
+
+  RegExpMacroAssembler();
+  virtual ~RegExpMacroAssembler();
+  virtual void AdvanceCurrentPosition(int by) = 0;  // Signed cp change.
+  virtual void AdvanceRegister(int reg, int by) = 0;  // r[reg] += by.
+  virtual void Backtrack() = 0;
+  virtual void Bind(Label* label) = 0;
+  // Check the current character against a bitmap.  The range of the current
+  // character must be from start to start + length_of_bitmap_in_bits.
+  virtual void CheckBitmap(
+      uc16 start,           // The bitmap is indexed from this character.
+      Label* bitmap,        // Where the bitmap is emitted.
+      Label* on_zero) = 0;  // Where to go if the bit is 0.  Fall through on 1.
+  // Dispatch after looking the current character up in a 2-bits-per-entry
+  // map.  The destinations vector has up to 4 labels.
+  virtual void CheckCharacter(uc16 c, Label* on_equal) = 0;
+  virtual void CheckCharacterGT(uc16 limit, Label* on_greater) = 0;
+  virtual void CheckCharacterLT(uc16 limit, Label* on_less) = 0;
+  // Check the current character for a match with a literal string.  If we
+  // fail to match then goto the on_failure label.  End of input always
+  // matches.  If the label is NULL then we should pop a backtrack address off
+  // the stack abnd go to that.
+  virtual void CheckCharacters(
+      Vector<const uc16> str,
+      int cp_offset,
+      Label* on_failure) = 0;
+  // Check the current input position against a register.  If the register is
+  // equal to the current position then go to the label.  If the label is NULL
+  // then backtrack instead.
+  virtual void CheckCurrentPosition(
+      int register_index,
+      Label* on_equal) = 0;
+  virtual void CheckNotBackReference(int start_reg, Label* on_no_match) = 0;
+  // Check the current character for a match with a literal character.  If we
+  // fail to match then goto the on_failure label.  End of input always
+  // matches.  If the label is NULL then we should pop a backtrack address off
+  // the stack and go to that.
+  virtual void CheckNotCharacter(uc16 c, Label* on_not_equal) = 0;
+  // Bitwise or the current character with the given constant and then
+  // check for a match with c.
+  virtual void CheckNotCharacterAfterOr(uc16 c,
+                                        uc16 or_with,
+                                        Label* on_not_equal) = 0;
+  // Subtract a constant from the current character, then or with the given
+  // constant and then check for a match with c.
+  virtual void CheckNotCharacterAfterMinusOr(uc16 c,
+                                             uc16 minus_then_or_with,
+                                             Label* on_not_equal) = 0;
+  // Dispatch after looking the current character up in a byte map.  The
+  // destinations vector has up to 256 labels.
+  virtual void DispatchByteMap(
+      uc16 start,
+      Label* byte_map,
+      const Vector<Label*>& destinations) = 0;
+  virtual void DispatchHalfNibbleMap(
+      uc16 start,
+      Label* half_nibble_map,
+      const Vector<Label*>& destinations) = 0;
+  // Dispatch after looking the high byte of the current character up in a byte
+  // map.  The destinations vector has up to 256 labels.
+  virtual void DispatchHighByteMap(
+      byte start,
+      Label* byte_map,
+      const Vector<Label*>& destinations) = 0;
+  virtual void EmitOrLink(Label* label) = 0;
+  virtual void Fail() = 0;
+  virtual Handle<Object> GetCode() = 0;
+  virtual void GoTo(Label* label) = 0;
+  // Check whether a register is >= a given constant and go to a label if it
+  // is.  Backtracks instead if the label is NULL.
+  virtual void IfRegisterGE(int reg, int comparand, Label* if_ge) = 0;
+  // Check whether a register is < a given constant and go to a label if it is.
+  // Backtracks instead if the label is NULL.
+  virtual void IfRegisterLT(int reg, int comparand, Label* if_lt) = 0;
+  virtual IrregexpImplementation Implementation() = 0;
+  virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input) = 0;
+  virtual void PopCurrentPosition() = 0;
+  virtual void PopRegister(int register_index) = 0;
+  virtual void PushBacktrack(Label* label) = 0;
+  virtual void PushCurrentPosition() = 0;
+  virtual void PushRegister(int register_index) = 0;
+  virtual void ReadCurrentPositionFromRegister(int reg) = 0;
+  virtual void ReadStackPointerFromRegister(int reg) = 0;
+  virtual void SetRegister(int register_index, int to) = 0;
+  virtual void Succeed() = 0;
+  virtual void WriteCurrentPositionToRegister(int reg) = 0;
+  virtual void WriteStackPointerToRegister(int reg) = 0;
+
+ private:
+};
+
+
+struct ArraySlice {
+ public:
+  ArraySlice(Handle<ByteArray> array, size_t offset)
+    : array_(array), offset_(offset) {}
+  Handle<ByteArray> array() { return array_; }
+  // Offset in the byte array data.
+  size_t offset() { return offset_; }
+  // Offset from the ByteArray pointer.
+  size_t base_offset() {
+    return ByteArray::kHeaderSize - kHeapObjectTag + offset_;
+  }
+  template <typename T>
+  T* location() {
+    return reinterpret_cast<T*>(array_->GetDataStartAddress() + offset_);
+  }
+  template <typename T>
+  T& at(int idx) {
+    return reinterpret_cast<T*>(array_->GetDataStartAddress() + offset_)[idx];
+  }
+ private:
+  Handle<ByteArray> array_;
+  size_t offset_;
+};
+
+
+class ByteArrayProvider {
+ public:
+  explicit ByteArrayProvider(unsigned int initial_size);
+  // Provides a place to put "size" elements of size "element_size".
+  // The information can be stored in the provided ByteArray at the "offset".
+  // The offset is aligned to the element size.
+  ArraySlice GetBuffer(unsigned int size,
+                       unsigned int element_size);
+  template <typename T>
+  ArraySlice GetBuffer(Vector<T> values);
+ private:
+  size_t byte_array_size_;
+  Handle<ByteArray> current_byte_array_;
+  int current_byte_array_free_offset_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_REGEXP_MACRO_ASSEMBLER_H_
index 71b5fed..5ac9264 100644 (file)
@@ -288,7 +288,7 @@ static Object* Runtime_IsConstructCall(Arguments args) {
 
 
 static Object* Runtime_RegExpCompile(Arguments args) {
-  HandleScope scope;  // create a new handle scope
+  HandleScope scope;
   ASSERT(args.length() == 3);
   CONVERT_CHECKED(JSRegExp, raw_re, args[0]);
   Handle<JSRegExp> re(raw_re);
@@ -786,7 +786,9 @@ static Object* Runtime_RegExpExec(Arguments args) {
   Handle<String> subject(raw_subject);
   Handle<Object> index(args[2]);
   ASSERT(index->IsNumber());
-  return *RegExpImpl::Exec(regexp, subject, index);
+  Handle<Object> result = RegExpImpl::Exec(regexp, subject, index);
+  if (result.is_null()) return Failure::Exception();
+  return *result;
 }
 
 
@@ -797,7 +799,9 @@ static Object* Runtime_RegExpExecGlobal(Arguments args) {
   Handle<JSRegExp> regexp(raw_regexp);
   CONVERT_CHECKED(String, raw_subject, args[1]);
   Handle<String> subject(raw_subject);
-  return *RegExpImpl::ExecGlobal(regexp, subject);
+  Handle<Object> result = RegExpImpl::ExecGlobal(regexp, subject);
+  if (result.is_null()) return Failure::Exception();
+  return *result;
 }
 
 
@@ -2444,7 +2448,7 @@ static Object* ConvertCase(Arguments args,
   // in the buffer
   Access<StringInputBuffer> buffer(&string_input_buffer);
   buffer->Reset(s);
-  unibrow::uchar chars[unibrow::kMaxCaseConvertedSize];
+  unibrow::uchar chars[Converter::kMaxWidth];
   int i = 0;
   // We can assume that the string is not empty
   uc32 current = buffer->GetNext();
index 6a3737b..f311e20 100644 (file)
@@ -93,13 +93,13 @@ static bool IsControlChar(char c) {
 }
 
 
-void StringStream::Add(const char* format, Vector<FmtElm> elms) {
+void StringStream::Add(Vector<const char> format, Vector<FmtElm> elms) {
   // If we already ran out of space then return immediately.
   if (space() == 0)
     return;
   int offset = 0;
   int elm = 0;
-  while (format[offset] != '\0') {
+  while (offset < format.length()) {
     if (format[offset] != '%' || elm == elms.length()) {
       Put(format[offset]);
       offset++;
@@ -111,12 +111,11 @@ void StringStream::Add(const char* format, Vector<FmtElm> elms) {
     // Skip over the whole control character sequence until the
     // format element type
     temp[format_length++] = format[offset++];
-    // '\0' is not a control character so we don't have to
-    // explicitly check for the end of the string
-    while (IsControlChar(format[offset]))
+    while (offset < format.length() && IsControlChar(format[offset]))
       temp[format_length++] = format[offset++];
+    if (offset >= format.length())
+      return;
     char type = format[offset];
-    if (type == '\0') return;
     temp[format_length++] = type;
     temp[format_length] = '\0';
     offset++;
@@ -128,17 +127,36 @@ void StringStream::Add(const char* format, Vector<FmtElm> elms) {
       Add(value);
       break;
     }
+    case 'w': {
+      ASSERT_EQ(FmtElm::LC_STR, current.type_);
+      Vector<const uc16> value = *current.data_.u_lc_str_;
+      for (int i = 0; i < value.length(); i++)
+        Put(static_cast<char>(value[i]));
+      break;
+    }
     case 'o': {
       ASSERT_EQ(FmtElm::OBJ, current.type_);
       Object* obj = current.data_.u_obj_;
       PrintObject(obj);
       break;
     }
-    case 'i': case 'd': case 'u': case 'x': case 'c': case 'p': {
+    case 'k': {
+      ASSERT_EQ(FmtElm::INT, current.type_);
+      int value = current.data_.u_int_;
+      if (0x20 <= value && value <= 0x7F) {
+        Put(value);
+      } else if (value <= 0xff) {
+        Add("\\x%02x", value);
+      } else {
+        Add("\\u%04x", value);
+      }
+      break;
+    }
+    case 'i': case 'd': case 'u': case 'x': case 'c': case 'p': case 'X': {
       int value = current.data_.u_int_;
       EmbeddedVector<char, 24> formatted;
-      OS::SNPrintF(formatted, temp.start(), value);
-      Add(formatted.start());
+      int length = OS::SNPrintF(formatted, temp.start(), value);
+      Add(Vector<const char>(formatted.start(), length));
       break;
     }
     case 'f': case 'g': case 'G': case 'e': case 'E': {
@@ -154,10 +172,8 @@ void StringStream::Add(const char* format, Vector<FmtElm> elms) {
     }
   }
 
-  // Verify that the buffer is 0-terminated and doesn't contain any
-  // other 0-characters.
+  // Verify that the buffer is 0-terminated
   ASSERT(buffer_[length_] == '\0');
-  ASSERT(strlen(buffer_) == length_);
 }
 
 
@@ -188,6 +204,11 @@ void StringStream::PrintObject(Object* o) {
 
 
 void StringStream::Add(const char* format) {
+  Add(CStrVector(format));
+}
+
+
+void StringStream::Add(Vector<const char> format) {
   Add(format, Vector<FmtElm>::empty());
 }
 
@@ -195,14 +216,14 @@ void StringStream::Add(const char* format) {
 void StringStream::Add(const char* format, FmtElm arg0) {
   const char argc = 1;
   FmtElm argv[argc] = { arg0 };
-  Add(format, Vector<FmtElm>(argv, argc));
+  Add(CStrVector(format), Vector<FmtElm>(argv, argc));
 }
 
 
 void StringStream::Add(const char* format, FmtElm arg0, FmtElm arg1) {
   const char argc = 2;
   FmtElm argv[argc] = { arg0, arg1 };
-  Add(format, Vector<FmtElm>(argv, argc));
+  Add(CStrVector(format), Vector<FmtElm>(argv, argc));
 }
 
 
@@ -210,7 +231,15 @@ void StringStream::Add(const char* format, FmtElm arg0, FmtElm arg1,
                        FmtElm arg2) {
   const char argc = 3;
   FmtElm argv[argc] = { arg0, arg1, arg2 };
-  Add(format, Vector<FmtElm>(argv, argc));
+  Add(CStrVector(format), Vector<FmtElm>(argv, argc));
+}
+
+
+void StringStream::Add(const char* format, FmtElm arg0, FmtElm arg1,
+                       FmtElm arg2, FmtElm arg3) {
+  const char argc = 4;
+  FmtElm argv[argc] = { arg0, arg1, arg2, arg3 };
+  Add(CStrVector(format), Vector<FmtElm>(argv, argc));
 }
 
 
index 2fb29af..37ae93e 100644 (file)
@@ -75,17 +75,19 @@ class FmtElm {
   FmtElm(int value) : type_(INT) { data_.u_int_ = value; }  // NOLINT
   explicit FmtElm(double value) : type_(DOUBLE) { data_.u_double_ = value; }  // NOLINT
   FmtElm(const char* value) : type_(C_STR) { data_.u_c_str_ = value; }  // NOLINT
+  FmtElm(const Vector<const uc16>& value) : type_(LC_STR) { data_.u_lc_str_ = &value; } // NOLINT
   FmtElm(Object* value) : type_(OBJ) { data_.u_obj_ = value; }  // NOLINT
   FmtElm(Handle<Object> value) : type_(HANDLE) { data_.u_handle_ = value.location(); }  // NOLINT
   FmtElm(void* value) : type_(INT) { data_.u_int_ = reinterpret_cast<int>(value); }  // NOLINT
  private:
   friend class StringStream;
-  enum Type { INT, DOUBLE, C_STR, OBJ, HANDLE };
+  enum Type { INT, DOUBLE, C_STR, LC_STR, OBJ, HANDLE };
   Type type_;
   union {
     int u_int_;
     double u_double_;
     const char* u_c_str_;
+    const Vector<const uc16>* u_lc_str_;
     Object* u_obj_;
     Object** u_handle_;
   } data_;
@@ -108,11 +110,17 @@ class StringStream {
   bool Put(char c);
   bool Put(String* str);
   bool Put(String* str, int start, int end);
-  void Add(const char* format, Vector<FmtElm> elms);
+  void Add(Vector<const char> format, Vector<FmtElm> elms);
   void Add(const char* format);
+  void Add(Vector<const char> format);
   void Add(const char* format, FmtElm arg0);
   void Add(const char* format, FmtElm arg0, FmtElm arg1);
   void Add(const char* format, FmtElm arg0, FmtElm arg1, FmtElm arg2);
+  void Add(const char* format,
+           FmtElm arg0,
+           FmtElm arg1,
+           FmtElm arg2,
+           FmtElm arg3);
 
   // Getting the message out.
   void OutputToStdOut();
index 3ee1b9e..f5f00ae 100644 (file)
@@ -892,7 +892,7 @@ Object* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
 Object* StubCompiler::GetCodeWithFlags(Code::Flags flags) {
   CodeDesc desc;
   masm_.GetCode(&desc);
-  Object* result = Heap::CreateCode(desc, NULL, flags);
+  Object* result = Heap::CreateCode(desc, NULL, flags, NULL);
 #ifdef DEBUG
   if (FLAG_print_code_stubs && !result->IsFailure()) {
     Code::cast(result)->Print();
index 2f70bd3..ecc5047 100644 (file)
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 //
-// This file was generated at 2008-10-01 18:05:45.480436
+// This file was generated at 2008-11-24 14:11:36.319039
 
 #include "unicode-inl.h"
 #include <cstdlib>
@@ -33,6 +33,9 @@
 
 namespace unibrow {
 
+static const int kStartBit = (1 << 30);
+static const int kChunkBits = (1 << 15);
+
 /**
  * \file
  * Implementations of functions for working with unicode.
@@ -40,19 +43,20 @@ namespace unibrow {
 
 typedef signed short int16_t;  // NOLINT
 typedef unsigned short uint16_t;  // NOLINT
+typedef int int32_t;  // NOLINT
 
 // All access to the character table should go through this function.
 template <int D>
-static inline uchar TableGet(const uint16_t* table, int index) {
+static inline uchar TableGet(const int32_t* table, int index) {
   return table[D * index];
 }
 
-static inline uchar GetEntry(uint16_t entry) {
-  return entry & 0x7fff;
+static inline uchar GetEntry(int32_t entry) {
+  return entry & (kStartBit - 1);
 }
 
-static inline bool IsStart(uint16_t entry) {
-  return (entry & (1 << 15)) != 0;
+static inline bool IsStart(int32_t entry) {
+  return (entry & kStartBit) != 0;
 }
 
 /**
@@ -65,9 +69,9 @@ static inline bool IsStart(uint16_t entry) {
  * about a character is around 10, slightly higher if there is no
  * information available about the character.
  */
-static bool LookupPredicate(const uint16_t* table, uint16_t size, uchar chr) {
+static bool LookupPredicate(const int32_t* table, uint16_t size, uchar chr) {
   static const int kEntryDist = 1;
-  uint16_t value = chr & 0x7fff;
+  uint16_t value = chr & (kChunkBits - 1);
   unsigned int low = 0;
   unsigned int high = size - 1;
   while (high != low) {
@@ -89,14 +93,17 @@ static bool LookupPredicate(const uint16_t* table, uint16_t size, uchar chr) {
       high = mid - 1;
     }
   }
-  uint16_t field = TableGet<kEntryDist>(table, low);
-  return (GetEntry(field) == value) ||
-          (GetEntry(field) < value && IsStart(field));
+  int32_t field = TableGet<kEntryDist>(table, low);
+  uchar entry = GetEntry(field);
+  bool is_start = IsStart(field);
+  return (entry == value) ||
+          (entry < value && is_start);
 }
 
+template <int kW>
 struct MultiCharacterSpecialCase {
   uint16_t length;
-  uchar chars[kMaxCaseConvertedSize];
+  uchar chars[kW];
 };
 
 // Look up the mapping for the given character in the specified table,
@@ -107,11 +114,16 @@ struct MultiCharacterSpecialCase {
 // if the allow_caching_ptr is non-null then false will be stored in
 // it if the result contains multiple characters or depends on the
 // context.
-static int LookupMapping(const uint16_t* table, uint16_t size,
-    const MultiCharacterSpecialCase* multi_chars, uchar chr, uchar next,
-    uchar* result, bool* allow_caching_ptr) {
+template <int kW>
+static int LookupMapping(const int32_t* table,
+                         uint16_t size,
+                         const MultiCharacterSpecialCase<kW>* multi_chars,
+                         uchar chr,
+                         uchar next,
+                         uchar* result,
+                         bool* allow_caching_ptr) {
   static const int kEntryDist = 2;
-  uint16_t value = chr & 0x7fff;
+  uint16_t value = chr & (kChunkBits - 1);
   unsigned int low = 0;
   unsigned int high = size - 1;
   while (high != low) {
@@ -133,11 +145,12 @@ static int LookupMapping(const uint16_t* table, uint16_t size,
       high = mid - 1;
     }
   }
-  uint16_t field = TableGet<kEntryDist>(table, low);
-  bool found = (GetEntry(field) == value) ||
-               (GetEntry(field) < value && IsStart(field));
+  int32_t field = TableGet<kEntryDist>(table, low);
+  uchar entry = GetEntry(field);
+  bool is_start = IsStart(field);
+  bool found = (entry == value) || (entry < value && is_start);
   if (found) {
-    int16_t value = table[2 * low + 1];
+    int32_t value = table[2 * low + 1];
     if (value == 0) {
       // 0 means not present
       return 0;
@@ -148,7 +161,7 @@ static int LookupMapping(const uint16_t* table, uint16_t size,
     } else if ((value & 3) == 1) {
       // Low bits 1 means a special case mapping
       if (allow_caching_ptr) *allow_caching_ptr = false;
-      const MultiCharacterSpecialCase& mapping = multi_chars[value >> 2];
+      const MultiCharacterSpecialCase<kW>& mapping = multi_chars[value >> 2];
       for (int i = 0; i < mapping.length; i++)
         result[i] = mapping.chars[i];
       return mapping.length;
@@ -323,13 +336,13 @@ void CharacterStream::Seek(unsigned position) {
 // Uppercase:            point.category == 'Lu'
 
 static const uint16_t kUppercaseTable0Size = 509;
-static const uint16_t kUppercaseTable0[509] = { 32833, 90, 32960, 214, 32984, 222, 256, 258, 260, 262, 264, 266, 268, 270, 272, 274, 276, 278, 280, 282, 284, 286, 288, 290, 292, 294, 296, 298, 300, 302, 304, 306, 308, 310, 313, 315, 317, 319, 321, 323, 325, 327, 330, 332, 334, 336, 338, 340, 342, 344, 346, 348, 350, 352, 354, 356, 358, 360, 362, 364, 366, 368, 370, 372, 374, 33144, 377, 379, 381, 33153, 386, 388, 33158, 391, 33161, 395, 33166, 401, 33171, 404, 33174, 408, 33180, 413, 33183, 416, 418, 420, 33190, 423, 425, 428, 33198, 431, 33201, 435, 437, 33207, 440, 444, 452, 455, 458, 461, 463, 465, 467, 469, 471, 473, 475, 478, 480, 482, 484, 486, 488, 490, 492, 494, 497, 500, 33270, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, 532, 534, 536, 538, 540, 542, 544, 546, 548, 550, 552, 554, 556, 558, 560, 562, 33338, 571, 33341, 574, 577, 33347, 582, 584, 586, 588, 590, 902, 33672, 906, 908, 33678, 911, 33681, 929, 33699, 939, 33746, 980, 984, 986, 988, 990, 992, 994, 996, 998, 1000, 1002, 1004, 1006, 1012, 1015, 33785, 1018, 33789, 1071, 1120, 1122, 1124, 1126, 1128, 1130, 1132, 1134, 1136, 1138, 1140, 1142, 1144, 1146, 1148, 1150, 1152, 1162, 1164, 1166, 1168, 1170, 1172, 1174, 1176, 1178, 1180, 1182, 1184, 1186, 1188, 1190, 1192, 1194, 1196, 1198, 1200, 1202, 1204, 1206, 1208, 1210, 1212, 1214, 33984, 1217, 1219, 1221, 1223, 1225, 1227, 1229, 1232, 1234, 1236, 1238, 1240, 1242, 1244, 1246, 1248, 1250, 1252, 1254, 1256, 1258, 1260, 1262, 1264, 1266, 1268, 1270, 1272, 1274, 1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294, 1296, 1298, 34097, 1366, 37024, 4293, 7680, 7682, 7684, 7686, 7688, 7690, 7692, 7694, 7696, 7698, 7700, 7702, 7704, 7706, 7708, 7710, 7712, 7714, 7716, 7718, 7720, 7722, 7724, 7726, 7728, 7730, 7732, 7734, 7736, 7738, 7740, 7742, 7744, 7746, 7748, 7750, 7752, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774, 7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, 7794, 7796, 7798, 7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822, 7824, 7826, 7828, 7840, 7842, 7844, 7846, 7848, 7850, 7852, 7854, 7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870, 7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892, 7894, 7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918, 7920, 7922, 7924, 7926, 7928, 40712, 7951, 40728, 7965, 40744, 7983, 40760, 7999, 40776, 8013, 8025, 8027, 8029, 8031, 40808, 8047, 40888, 8123, 40904, 8139, 40920, 8155, 40936, 8172, 40952, 8187, 8450, 8455, 41227, 8461, 41232, 8466, 8469, 41241, 8477, 8484, 8486, 8488, 41258, 8493, 41264, 8499, 41278, 8511, 8517, 8579, 44032, 11310, 11360, 44130, 11364, 11367, 11369, 11371, 11381, 11392, 11394, 11396, 11398, 11400, 11402, 11404, 11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420, 11422, 11424, 11426, 11428, 11430, 11432, 11434, 11436, 11438, 11440, 11442, 11444, 11446, 11448, 11450, 11452, 11454, 11456, 11458, 11460, 11462, 11464, 11466, 11468, 11470, 11472, 11474, 11476, 11478, 11480, 11482, 11484, 11486, 11488, 11490 }; // NOLINT
+static const int32_t kUppercaseTable0[509] = { 1073741889, 90, 1073742016, 214, 1073742040, 222, 256, 258, 260, 262, 264, 266, 268, 270, 272, 274, 276, 278, 280, 282, 284, 286, 288, 290, 292, 294, 296, 298, 300, 302, 304, 306, 308, 310, 313, 315, 317, 319, 321, 323, 325, 327, 330, 332, 334, 336, 338, 340, 342, 344, 346, 348, 350, 352, 354, 356, 358, 360, 362, 364, 366, 368, 370, 372, 374, 1073742200, 377, 379, 381, 1073742209, 386, 388, 1073742214, 391, 1073742217, 395, 1073742222, 401, 1073742227, 404, 1073742230, 408, 1073742236, 413, 1073742239, 416, 418, 420, 1073742246, 423, 425, 428, 1073742254, 431, 1073742257, 435, 437, 1073742263, 440, 444, 452, 455, 458, 461, 463, 465, 467, 469, 471, 473, 475, 478, 480, 482, 484, 486, 488, 490, 492, 494, 497, 500, 1073742326, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, 532, 534, 536, 538, 540, 542, 544, 546, 548, 550, 552, 554, 556, 558, 560, 562, 1073742394, 571, 1073742397, 574, 577, 1073742403, 582, 584, 586, 588, 590, 902, 1073742728, 906, 908, 1073742734, 911, 1073742737, 929, 1073742755, 939, 1073742802, 980, 984, 986, 988, 990, 992, 994, 996, 998, 1000, 1002, 1004, 1006, 1012, 1015, 1073742841, 1018, 1073742845, 1071, 1120, 1122, 1124, 1126, 1128, 1130, 1132, 1134, 1136, 1138, 1140, 1142, 1144, 1146, 1148, 1150, 1152, 1162, 1164, 1166, 1168, 1170, 1172, 1174, 1176, 1178, 1180, 1182, 1184, 1186, 1188, 1190, 1192, 1194, 1196, 1198, 1200, 1202, 1204, 1206, 1208, 1210, 1212, 1214, 1073743040, 1217, 1219, 1221, 1223, 1225, 1227, 1229, 1232, 1234, 1236, 1238, 1240, 1242, 1244, 1246, 1248, 1250, 1252, 1254, 1256, 1258, 1260, 1262, 1264, 1266, 1268, 1270, 1272, 1274, 1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294, 1296, 1298, 1073743153, 1366, 1073746080, 4293, 7680, 7682, 7684, 7686, 7688, 7690, 7692, 7694, 7696, 7698, 7700, 7702, 7704, 7706, 7708, 7710, 7712, 7714, 7716, 7718, 7720, 7722, 7724, 7726, 7728, 7730, 7732, 7734, 7736, 7738, 7740, 7742, 7744, 7746, 7748, 7750, 7752, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774, 7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, 7794, 7796, 7798, 7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822, 7824, 7826, 7828, 7840, 7842, 7844, 7846, 7848, 7850, 7852, 7854, 7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870, 7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892, 7894, 7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918, 7920, 7922, 7924, 7926, 7928, 1073749768, 7951, 1073749784, 7965, 1073749800, 7983, 1073749816, 7999, 1073749832, 8013, 8025, 8027, 8029, 8031, 1073749864, 8047, 1073749944, 8123, 1073749960, 8139, 1073749976, 8155, 1073749992, 8172, 1073750008, 8187, 8450, 8455, 1073750283, 8461, 1073750288, 8466, 8469, 1073750297, 8477, 8484, 8486, 8488, 1073750314, 8493, 1073750320, 8499, 1073750334, 8511, 8517, 8579, 1073753088, 11310, 11360, 1073753186, 11364, 11367, 11369, 11371, 11381, 11392, 11394, 11396, 11398, 11400, 11402, 11404, 11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420, 11422, 11424, 11426, 11428, 11430, 11432, 11434, 11436, 11438, 11440, 11442, 11444, 11446, 11448, 11450, 11452, 11454, 11456, 11458, 11460, 11462, 11464, 11466, 11468, 11470, 11472, 11474, 11476, 11478, 11480, 11482, 11484, 11486, 11488, 11490 }; // NOLINT
 static const uint16_t kUppercaseTable1Size = 2;
-static const uint16_t kUppercaseTable1[2] = { 65313, 32570 }; // NOLINT
+static const int32_t kUppercaseTable1[2] = { 1073774369, 32570 }; // NOLINT
 static const uint16_t kUppercaseTable2Size = 2;
-static const uint16_t kUppercaseTable2[2] = { 33792, 1063 }; // NOLINT
+static const int32_t kUppercaseTable2[2] = { 1073742848, 1063 }; // NOLINT
 static const uint16_t kUppercaseTable3Size = 58;
-static const uint16_t kUppercaseTable3[58] = { 54272, 21529, 54324, 21581, 54376, 21633, 21660, 54430, 21663, 21666, 54437, 21670, 54441, 21676, 54446, 21685, 54480, 21737, 54532, 21765, 54535, 21770, 54541, 21780, 54550, 21788, 54584, 21817, 54587, 21822, 54592, 21828, 21830, 54602, 21840, 54636, 21893, 54688, 21945, 54740, 21997, 54792, 22049, 54844, 22101, 54896, 22153, 54952, 22208, 55010, 22266, 55068, 22324, 55126, 22382, 55184, 22440, 22474 }; // NOLINT
+static const int32_t kUppercaseTable3[58] = { 1073763328, 21529, 1073763380, 21581, 1073763432, 21633, 21660, 1073763486, 21663, 21666, 1073763493, 21670, 1073763497, 21676, 1073763502, 21685, 1073763536, 21737, 1073763588, 21765, 1073763591, 21770, 1073763597, 21780, 1073763606, 21788, 1073763640, 21817, 1073763643, 21822, 1073763648, 21828, 21830, 1073763658, 21840, 1073763692, 21893, 1073763744, 21945, 1073763796, 21997, 1073763848, 22049, 1073763900, 22101, 1073763952, 22153, 1073764008, 22208, 1073764066, 22266, 1073764124, 22324, 1073764182, 22382, 1073764240, 22440, 22474 }; // NOLINT
 bool Uppercase::Is(uchar c) {
   int chunk_index = c >> 15;
   switch (chunk_index) {
@@ -352,13 +365,13 @@ bool Uppercase::Is(uchar c) {
 // Lowercase:            point.category == 'Ll'
 
 static const uint16_t kLowercaseTable0Size = 528;
-static const uint16_t kLowercaseTable0[528] = { 32865, 122, 170, 181, 186, 32991, 246, 33016, 255, 257, 259, 261, 263, 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, 295, 297, 299, 301, 303, 305, 307, 309, 33079, 312, 314, 316, 318, 320, 322, 324, 326, 33096, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 378, 380, 33150, 384, 387, 389, 392, 33164, 397, 402, 405, 33177, 411, 414, 417, 419, 421, 424, 33194, 427, 429, 432, 436, 438, 33209, 442, 33213, 447, 454, 457, 460, 462, 464, 466, 468, 470, 472, 474, 33244, 477, 479, 481, 483, 485, 487, 489, 491, 493, 33263, 496, 499, 501, 505, 507, 509, 511, 513, 515, 517, 519, 521, 523, 525, 527, 529, 531, 533, 535, 537, 539, 541, 543, 545, 547, 549, 551, 553, 555, 557, 559, 561, 33331, 569, 572, 33343, 576, 578, 583, 585, 587, 589, 33359, 659, 33429, 687, 33659, 893, 912, 33708, 974, 33744, 977, 33749, 983, 985, 987, 989, 991, 993, 995, 997, 999, 1001, 1003, 1005, 33775, 1011, 1013, 1016, 33787, 1020, 33840, 1119, 1121, 1123, 1125, 1127, 1129, 1131, 1133, 1135, 1137, 1139, 1141, 1143, 1145, 1147, 1149, 1151, 1153, 1163, 1165, 1167, 1169, 1171, 1173, 1175, 1177, 1179, 1181, 1183, 1185, 1187, 1189, 1191, 1193, 1195, 1197, 1199, 1201, 1203, 1205, 1207, 1209, 1211, 1213, 1215, 1218, 1220, 1222, 1224, 1226, 1228, 33998, 1231, 1233, 1235, 1237, 1239, 1241, 1243, 1245, 1247, 1249, 1251, 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1271, 1273, 1275, 1277, 1279, 1281, 1283, 1285, 1287, 1289, 1291, 1293, 1295, 1297, 1299, 34145, 1415, 40192, 7467, 40290, 7543, 40313, 7578, 7681, 7683, 7685, 7687, 7689, 7691, 7693, 7695, 7697, 7699, 7701, 7703, 7705, 7707, 7709, 7711, 7713, 7715, 7717, 7719, 7721, 7723, 7725, 7727, 7729, 7731, 7733, 7735, 7737, 7739, 7741, 7743, 7745, 7747, 7749, 7751, 7753, 7755, 7757, 7759, 7761, 7763, 7765, 7767, 7769, 7771, 7773, 7775, 7777, 7779, 7781, 7783, 7785, 7787, 7789, 7791, 7793, 7795, 7797, 7799, 7801, 7803, 7805, 7807, 7809, 7811, 7813, 7815, 7817, 7819, 7821, 7823, 7825, 7827, 40597, 7835, 7841, 7843, 7845, 7847, 7849, 7851, 7853, 7855, 7857, 7859, 7861, 7863, 7865, 7867, 7869, 7871, 7873, 7875, 7877, 7879, 7881, 7883, 7885, 7887, 7889, 7891, 7893, 7895, 7897, 7899, 7901, 7903, 7905, 7907, 7909, 7911, 7913, 7915, 7917, 7919, 7921, 7923, 7925, 7927, 7929, 40704, 7943, 40720, 7957, 40736, 7975, 40752, 7991, 40768, 8005, 40784, 8023, 40800, 8039, 40816, 8061, 40832, 8071, 40848, 8087, 40864, 8103, 40880, 8116, 40886, 8119, 8126, 40898, 8132, 40902, 8135, 40912, 8147, 40918, 8151, 40928, 8167, 40946, 8180, 40950, 8183, 8305, 8319, 8458, 41230, 8463, 8467, 8495, 8500, 8505, 41276, 8509, 41286, 8521, 8526, 8580, 44080, 11358, 11361, 44133, 11366, 11368, 11370, 11372, 11380, 44150, 11383, 11393, 11395, 11397, 11399, 11401, 11403, 11405, 11407, 11409, 11411, 11413, 11415, 11417, 11419, 11421, 11423, 11425, 11427, 11429, 11431, 11433, 11435, 11437, 11439, 11441, 11443, 11445, 11447, 11449, 11451, 11453, 11455, 11457, 11459, 11461, 11463, 11465, 11467, 11469, 11471, 11473, 11475, 11477, 11479, 11481, 11483, 11485, 11487, 11489, 44259, 11492, 44288, 11557 }; // NOLINT
+static const int32_t kLowercaseTable0[528] = { 1073741921, 122, 170, 181, 186, 1073742047, 246, 1073742072, 255, 257, 259, 261, 263, 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, 295, 297, 299, 301, 303, 305, 307, 309, 1073742135, 312, 314, 316, 318, 320, 322, 324, 326, 1073742152, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 378, 380, 1073742206, 384, 387, 389, 392, 1073742220, 397, 402, 405, 1073742233, 411, 414, 417, 419, 421, 424, 1073742250, 427, 429, 432, 436, 438, 1073742265, 442, 1073742269, 447, 454, 457, 460, 462, 464, 466, 468, 470, 472, 474, 1073742300, 477, 479, 481, 483, 485, 487, 489, 491, 493, 1073742319, 496, 499, 501, 505, 507, 509, 511, 513, 515, 517, 519, 521, 523, 525, 527, 529, 531, 533, 535, 537, 539, 541, 543, 545, 547, 549, 551, 553, 555, 557, 559, 561, 1073742387, 569, 572, 1073742399, 576, 578, 583, 585, 587, 589, 1073742415, 659, 1073742485, 687, 1073742715, 893, 912, 1073742764, 974, 1073742800, 977, 1073742805, 983, 985, 987, 989, 991, 993, 995, 997, 999, 1001, 1003, 1005, 1073742831, 1011, 1013, 1016, 1073742843, 1020, 1073742896, 1119, 1121, 1123, 1125, 1127, 1129, 1131, 1133, 1135, 1137, 1139, 1141, 1143, 1145, 1147, 1149, 1151, 1153, 1163, 1165, 1167, 1169, 1171, 1173, 1175, 1177, 1179, 1181, 1183, 1185, 1187, 1189, 1191, 1193, 1195, 1197, 1199, 1201, 1203, 1205, 1207, 1209, 1211, 1213, 1215, 1218, 1220, 1222, 1224, 1226, 1228, 1073743054, 1231, 1233, 1235, 1237, 1239, 1241, 1243, 1245, 1247, 1249, 1251, 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1271, 1273, 1275, 1277, 1279, 1281, 1283, 1285, 1287, 1289, 1291, 1293, 1295, 1297, 1299, 1073743201, 1415, 1073749248, 7467, 1073749346, 7543, 1073749369, 7578, 7681, 7683, 7685, 7687, 7689, 7691, 7693, 7695, 7697, 7699, 7701, 7703, 7705, 7707, 7709, 7711, 7713, 7715, 7717, 7719, 7721, 7723, 7725, 7727, 7729, 7731, 7733, 7735, 7737, 7739, 7741, 7743, 7745, 7747, 7749, 7751, 7753, 7755, 7757, 7759, 7761, 7763, 7765, 7767, 7769, 7771, 7773, 7775, 7777, 7779, 7781, 7783, 7785, 7787, 7789, 7791, 7793, 7795, 7797, 7799, 7801, 7803, 7805, 7807, 7809, 7811, 7813, 7815, 7817, 7819, 7821, 7823, 7825, 7827, 1073749653, 7835, 7841, 7843, 7845, 7847, 7849, 7851, 7853, 7855, 7857, 7859, 7861, 7863, 7865, 7867, 7869, 7871, 7873, 7875, 7877, 7879, 7881, 7883, 7885, 7887, 7889, 7891, 7893, 7895, 7897, 7899, 7901, 7903, 7905, 7907, 7909, 7911, 7913, 7915, 7917, 7919, 7921, 7923, 7925, 7927, 7929, 1073749760, 7943, 1073749776, 7957, 1073749792, 7975, 1073749808, 7991, 1073749824, 8005, 1073749840, 8023, 1073749856, 8039, 1073749872, 8061, 1073749888, 8071, 1073749904, 8087, 1073749920, 8103, 1073749936, 8116, 1073749942, 8119, 8126, 1073749954, 8132, 1073749958, 8135, 1073749968, 8147, 1073749974, 8151, 1073749984, 8167, 1073750002, 8180, 1073750006, 8183, 8305, 8319, 8458, 1073750286, 8463, 8467, 8495, 8500, 8505, 1073750332, 8509, 1073750342, 8521, 8526, 8580, 1073753136, 11358, 11361, 1073753189, 11366, 11368, 11370, 11372, 11380, 1073753206, 11383, 11393, 11395, 11397, 11399, 11401, 11403, 11405, 11407, 11409, 11411, 11413, 11415, 11417, 11419, 11421, 11423, 11425, 11427, 11429, 11431, 11433, 11435, 11437, 11439, 11441, 11443, 11445, 11447, 11449, 11451, 11453, 11455, 11457, 11459, 11461, 11463, 11465, 11467, 11469, 11471, 11473, 11475, 11477, 11479, 11481, 11483, 11485, 11487, 11489, 1073753315, 11492, 1073753344, 11557 }; // NOLINT
 static const uint16_t kLowercaseTable1Size = 6;
-static const uint16_t kLowercaseTable1[6] = { 64256, 31494, 64275, 31511, 65345, 32602 }; // NOLINT
+static const int32_t kLowercaseTable1[6] = { 1073773312, 31494, 1073773331, 31511, 1073774401, 32602 }; // NOLINT
 static const uint16_t kLowercaseTable2Size = 2;
-static const uint16_t kLowercaseTable2[2] = { 33832, 1103 }; // NOLINT
+static const int32_t kLowercaseTable2[2] = { 1073742888, 1103 }; // NOLINT
 static const uint16_t kLowercaseTable3Size = 54;
-static const uint16_t kLowercaseTable3[54] = { 54298, 21555, 54350, 21588, 54358, 21607, 54402, 21659, 54454, 21689, 21691, 54461, 21699, 54469, 21711, 54506, 21763, 54558, 21815, 54610, 21867, 54662, 21919, 54714, 21971, 54766, 22023, 54818, 22075, 54870, 22127, 54922, 22181, 54978, 22234, 55004, 22241, 55036, 22292, 55062, 22299, 55094, 22350, 55120, 22357, 55152, 22408, 55178, 22415, 55210, 22466, 55236, 22473, 22475 }; // NOLINT
+static const int32_t kLowercaseTable3[54] = { 1073763354, 21555, 1073763406, 21588, 1073763414, 21607, 1073763458, 21659, 1073763510, 21689, 21691, 1073763517, 21699, 1073763525, 21711, 1073763562, 21763, 1073763614, 21815, 1073763666, 21867, 1073763718, 21919, 1073763770, 21971, 1073763822, 22023, 1073763874, 22075, 1073763926, 22127, 1073763978, 22181, 1073764034, 22234, 1073764060, 22241, 1073764092, 22292, 1073764118, 22299, 1073764150, 22350, 1073764176, 22357, 1073764208, 22408, 1073764234, 22415, 1073764266, 22466, 1073764292, 22473, 22475 }; // NOLINT
 bool Lowercase::Is(uchar c) {
   int chunk_index = c >> 15;
   switch (chunk_index) {
@@ -381,17 +394,17 @@ bool Lowercase::Is(uchar c) {
 // Letter:               point.category in ['Lu', 'Ll', 'Lt', 'Lm', 'Lo' ]
 
 static const uint16_t kLetterTable0Size = 476;
-static const uint16_t kLetterTable0[476] = { 32833, 90, 32865, 122, 170, 181, 186, 32960, 214, 32984, 246, 33016, 705, 33478, 721, 33504, 740, 750, 33658, 893, 902, 33672, 906, 908, 33678, 929, 33699, 974, 33744, 1013, 33783, 1153, 33930, 1299, 34097, 1366, 1369, 34145, 1415, 34256, 1514, 34288, 1522, 34337, 1594, 34368, 1610, 34414, 1647, 34417, 1747, 1749, 34533, 1766, 34542, 1775, 34554, 1788, 1791, 1808, 34578, 1839, 34637, 1901, 34688, 1957, 1969, 34762, 2026, 34804, 2037, 2042, 35076, 2361, 2365, 2384, 35160, 2401, 35195, 2431, 35205, 2444, 35215, 2448, 35219, 2472, 35242, 2480, 2482, 35254, 2489, 2493, 2510, 35292, 2525, 35295, 2529, 35312, 2545, 35333, 2570, 35343, 2576, 35347, 2600, 35370, 2608, 35378, 2611, 35381, 2614, 35384, 2617, 35417, 2652, 2654, 35442, 2676, 35461, 2701, 35471, 2705, 35475, 2728, 35498, 2736, 35506, 2739, 35509, 2745, 2749, 2768, 35552, 2785, 35589, 2828, 35599, 2832, 35603, 2856, 35626, 2864, 35634, 2867, 35637, 2873, 2877, 35676, 2909, 35679, 2913, 2929, 2947, 35717, 2954, 35726, 2960, 35730, 2965, 35737, 2970, 2972, 35742, 2975, 35747, 2980, 35752, 2986, 35758, 3001, 35845, 3084, 35854, 3088, 35858, 3112, 35882, 3123, 35893, 3129, 35936, 3169, 35973, 3212, 35982, 3216, 35986, 3240, 36010, 3251, 36021, 3257, 3261, 3294, 36064, 3297, 36101, 3340, 36110, 3344, 36114, 3368, 36138, 3385, 36192, 3425, 36229, 3478, 36250, 3505, 36275, 3515, 3517, 36288, 3526, 36353, 3632, 36402, 3635, 36416, 3654, 36481, 3714, 3716, 36487, 3720, 3722, 3725, 36500, 3735, 36505, 3743, 36513, 3747, 3749, 3751, 36522, 3755, 36525, 3760, 36530, 3763, 3773, 36544, 3780, 3782, 36572, 3805, 3840, 36672, 3911, 36681, 3946, 36744, 3979, 36864, 4129, 36899, 4135, 36905, 4138, 36944, 4181, 37024, 4293, 37072, 4346, 4348, 37120, 4441, 37215, 4514, 37288, 4601, 37376, 4680, 37450, 4685, 37456, 4694, 4696, 37466, 4701, 37472, 4744, 37514, 4749, 37520, 4784, 37554, 4789, 37560, 4798, 4800, 37570, 4805, 37576, 4822, 37592, 4880, 37650, 4885, 37656, 4954, 37760, 5007, 37792, 5108, 37889, 5740, 38511, 5750, 38529, 5786, 38560, 5866, 38656, 5900, 38670, 5905, 38688, 5937, 38720, 5969, 38752, 5996, 38766, 6000, 38784, 6067, 6103, 6108, 38944, 6263, 39040, 6312, 39168, 6428, 39248, 6509, 39280, 6516, 39296, 6569, 39361, 6599, 39424, 6678, 39685, 6963, 39749, 6987, 40192, 7615, 40448, 7835, 40608, 7929, 40704, 7957, 40728, 7965, 40736, 8005, 40776, 8013, 40784, 8023, 8025, 8027, 8029, 40799, 8061, 40832, 8116, 40886, 8124, 8126, 40898, 8132, 40902, 8140, 40912, 8147, 40918, 8155, 40928, 8172, 40946, 8180, 40950, 8188, 8305, 8319, 41104, 8340, 8450, 8455, 41226, 8467, 8469, 41241, 8477, 8484, 8486, 8488, 41258, 8493, 41263, 8505, 41276, 8511, 41285, 8521, 8526, 41347, 8580, 44032, 11310, 44080, 11358, 44128, 11372, 44148, 11383, 44160, 11492, 44288, 11557, 44336, 11621, 11631, 44416, 11670, 44448, 11686, 44456, 11694, 44464, 11702, 44472, 11710, 44480, 11718, 44488, 11726, 44496, 11734, 44504, 11742, 45061, 12294, 45105, 12341, 45115, 12348, 45121, 12438, 45213, 12447, 45217, 12538, 45308, 12543, 45317, 12588, 45361, 12686, 45472, 12727, 45552, 12799, 46080, 19893, 52736, 32767 }; // NOLINT
+static const int32_t kLetterTable0[476] = { 1073741889, 90, 1073741921, 122, 170, 181, 186, 1073742016, 214, 1073742040, 246, 1073742072, 705, 1073742534, 721, 1073742560, 740, 750, 1073742714, 893, 902, 1073742728, 906, 908, 1073742734, 929, 1073742755, 974, 1073742800, 1013, 1073742839, 1153, 1073742986, 1299, 1073743153, 1366, 1369, 1073743201, 1415, 1073743312, 1514, 1073743344, 1522, 1073743393, 1594, 1073743424, 1610, 1073743470, 1647, 1073743473, 1747, 1749, 1073743589, 1766, 1073743598, 1775, 1073743610, 1788, 1791, 1808, 1073743634, 1839, 1073743693, 1901, 1073743744, 1957, 1969, 1073743818, 2026, 1073743860, 2037, 2042, 1073744132, 2361, 2365, 2384, 1073744216, 2401, 1073744251, 2431, 1073744261, 2444, 1073744271, 2448, 1073744275, 2472, 1073744298, 2480, 2482, 1073744310, 2489, 2493, 2510, 1073744348, 2525, 1073744351, 2529, 1073744368, 2545, 1073744389, 2570, 1073744399, 2576, 1073744403, 2600, 1073744426, 2608, 1073744434, 2611, 1073744437, 2614, 1073744440, 2617, 1073744473, 2652, 2654, 1073744498, 2676, 1073744517, 2701, 1073744527, 2705, 1073744531, 2728, 1073744554, 2736, 1073744562, 2739, 1073744565, 2745, 2749, 2768, 1073744608, 2785, 1073744645, 2828, 1073744655, 2832, 1073744659, 2856, 1073744682, 2864, 1073744690, 2867, 1073744693, 2873, 2877, 1073744732, 2909, 1073744735, 2913, 2929, 2947, 1073744773, 2954, 1073744782, 2960, 1073744786, 2965, 1073744793, 2970, 2972, 1073744798, 2975, 1073744803, 2980, 1073744808, 2986, 1073744814, 3001, 1073744901, 3084, 1073744910, 3088, 1073744914, 3112, 1073744938, 3123, 1073744949, 3129, 1073744992, 3169, 1073745029, 3212, 1073745038, 3216, 1073745042, 3240, 1073745066, 3251, 1073745077, 3257, 3261, 3294, 1073745120, 3297, 1073745157, 3340, 1073745166, 3344, 1073745170, 3368, 1073745194, 3385, 1073745248, 3425, 1073745285, 3478, 1073745306, 3505, 1073745331, 3515, 3517, 1073745344, 3526, 1073745409, 3632, 1073745458, 3635, 1073745472, 3654, 1073745537, 3714, 3716, 1073745543, 3720, 3722, 3725, 1073745556, 3735, 1073745561, 3743, 1073745569, 3747, 3749, 3751, 1073745578, 3755, 1073745581, 3760, 1073745586, 3763, 3773, 1073745600, 3780, 3782, 1073745628, 3805, 3840, 1073745728, 3911, 1073745737, 3946, 1073745800, 3979, 1073745920, 4129, 1073745955, 4135, 1073745961, 4138, 1073746000, 4181, 1073746080, 4293, 1073746128, 4346, 4348, 1073746176, 4441, 1073746271, 4514, 1073746344, 4601, 1073746432, 4680, 1073746506, 4685, 1073746512, 4694, 4696, 1073746522, 4701, 1073746528, 4744, 1073746570, 4749, 1073746576, 4784, 1073746610, 4789, 1073746616, 4798, 4800, 1073746626, 4805, 1073746632, 4822, 1073746648, 4880, 1073746706, 4885, 1073746712, 4954, 1073746816, 5007, 1073746848, 5108, 1073746945, 5740, 1073747567, 5750, 1073747585, 5786, 1073747616, 5866, 1073747712, 5900, 1073747726, 5905, 1073747744, 5937, 1073747776, 5969, 1073747808, 5996, 1073747822, 6000, 1073747840, 6067, 6103, 6108, 1073748000, 6263, 1073748096, 6312, 1073748224, 6428, 1073748304, 6509, 1073748336, 6516, 1073748352, 6569, 1073748417, 6599, 1073748480, 6678, 1073748741, 6963, 1073748805, 6987, 1073749248, 7615, 1073749504, 7835, 1073749664, 7929, 1073749760, 7957, 1073749784, 7965, 1073749792, 8005, 1073749832, 8013, 1073749840, 8023, 8025, 8027, 8029, 1073749855, 8061, 1073749888, 8116, 1073749942, 8124, 8126, 1073749954, 8132, 1073749958, 8140, 1073749968, 8147, 1073749974, 8155, 1073749984, 8172, 1073750002, 8180, 1073750006, 8188, 8305, 8319, 1073750160, 8340, 8450, 8455, 1073750282, 8467, 8469, 1073750297, 8477, 8484, 8486, 8488, 1073750314, 8493, 1073750319, 8505, 1073750332, 8511, 1073750341, 8521, 8526, 1073750403, 8580, 1073753088, 11310, 1073753136, 11358, 1073753184, 11372, 1073753204, 11383, 1073753216, 11492, 1073753344, 11557, 1073753392, 11621, 11631, 1073753472, 11670, 1073753504, 11686, 1073753512, 11694, 1073753520, 11702, 1073753528, 11710, 1073753536, 11718, 1073753544, 11726, 1073753552, 11734, 1073753560, 11742, 1073754117, 12294, 1073754161, 12341, 1073754171, 12348, 1073754177, 12438, 1073754269, 12447, 1073754273, 12538, 1073754364, 12543, 1073754373, 12588, 1073754417, 12686, 1073754528, 12727, 1073754608, 12799, 1073755136, 19893, 1073761792, 32767 }; // NOLINT
 static const uint16_t kLetterTable1Size = 68;
-static const uint16_t kLetterTable1[68] = { 32768, 8123, 40960, 9356, 42775, 10010, 43008, 10241, 43011, 10245, 43015, 10250, 43020, 10274, 43072, 10355, 44032, 22435, 63744, 31277, 64048, 31338, 64112, 31449, 64256, 31494, 64275, 31511, 31517, 64287, 31528, 64298, 31542, 64312, 31548, 31550, 64320, 31553, 64323, 31556, 64326, 31665, 64467, 32061, 64848, 32143, 64914, 32199, 65008, 32251, 65136, 32372, 65142, 32508, 65313, 32570, 65345, 32602, 65382, 32702, 65474, 32711, 65482, 32719, 65490, 32727, 65498, 32732 }; // NOLINT
+static const int32_t kLetterTable1[68] = { 1073741824, 8123, 1073750016, 9356, 1073751831, 10010, 1073752064, 10241, 1073752067, 10245, 1073752071, 10250, 1073752076, 10274, 1073752128, 10355, 1073753088, 22435, 1073772800, 31277, 1073773104, 31338, 1073773168, 31449, 1073773312, 31494, 1073773331, 31511, 31517, 1073773343, 31528, 1073773354, 31542, 1073773368, 31548, 31550, 1073773376, 31553, 1073773379, 31556, 1073773382, 31665, 1073773523, 32061, 1073773904, 32143, 1073773970, 32199, 1073774064, 32251, 1073774192, 32372, 1073774198, 32508, 1073774369, 32570, 1073774401, 32602, 1073774438, 32702, 1073774530, 32711, 1073774538, 32719, 1073774546, 32727, 1073774554, 32732 }; // NOLINT
 static const uint16_t kLetterTable2Size = 48;
-static const uint16_t kLetterTable2[48] = { 32768, 11, 32781, 38, 32808, 58, 32828, 61, 32831, 77, 32848, 93, 32896, 250, 33536, 798, 33584, 832, 33602, 841, 33664, 925, 33696, 963, 33736, 975, 33792, 1181, 34816, 2053, 2056, 34826, 2101, 34871, 2104, 2108, 2111, 35072, 2325, 2560, 35344, 2579, 35349, 2583, 35353, 2611, 40960, 9070 }; // NOLINT
+static const int32_t kLetterTable2[48] = { 1073741824, 11, 1073741837, 38, 1073741864, 58, 1073741884, 61, 1073741887, 77, 1073741904, 93, 1073741952, 250, 1073742592, 798, 1073742640, 832, 1073742658, 841, 1073742720, 925, 1073742752, 963, 1073742792, 975, 1073742848, 1181, 1073743872, 2053, 2056, 1073743882, 2101, 1073743927, 2104, 2108, 2111, 1073744128, 2325, 2560, 1073744400, 2579, 1073744405, 2583, 1073744409, 2611, 1073750016, 9070 }; // NOLINT
 static const uint16_t kLetterTable3Size = 57;
-static const uint16_t kLetterTable3[57] = { 54272, 21588, 54358, 21660, 54430, 21663, 21666, 54437, 21670, 54441, 21676, 54446, 21689, 21691, 54461, 21699, 54469, 21765, 54535, 21770, 54541, 21780, 54550, 21788, 54558, 21817, 54587, 21822, 54592, 21828, 21830, 54602, 21840, 54610, 22181, 54952, 22208, 54978, 22234, 55004, 22266, 55036, 22292, 55062, 22324, 55094, 22350, 55120, 22382, 55152, 22408, 55178, 22440, 55210, 22466, 55236, 22475 }; // NOLINT
+static const int32_t kLetterTable3[57] = { 1073763328, 21588, 1073763414, 21660, 1073763486, 21663, 21666, 1073763493, 21670, 1073763497, 21676, 1073763502, 21689, 21691, 1073763517, 21699, 1073763525, 21765, 1073763591, 21770, 1073763597, 21780, 1073763606, 21788, 1073763614, 21817, 1073763643, 21822, 1073763648, 21828, 21830, 1073763658, 21840, 1073763666, 22181, 1073764008, 22208, 1073764034, 22234, 1073764060, 22266, 1073764092, 22292, 1073764118, 22324, 1073764150, 22350, 1073764176, 22382, 1073764208, 22408, 1073764234, 22440, 1073764266, 22466, 1073764292, 22475 }; // NOLINT
 static const uint16_t kLetterTable4Size = 2;
-static const uint16_t kLetterTable4[2] = { 32768, 32767 }; // NOLINT
+static const int32_t kLetterTable4[2] = { 1073741824, 32767 }; // NOLINT
 static const uint16_t kLetterTable5Size = 4;
-static const uint16_t kLetterTable5[4] = { 32768, 9942, 63488, 31261 }; // NOLINT
+static const int32_t kLetterTable5[4] = { 1073741824, 9942, 1073772544, 31261 }; // NOLINT
 bool Letter::Is(uchar c) {
   int chunk_index = c >> 15;
   switch (chunk_index) {
@@ -420,7 +433,7 @@ bool Letter::Is(uchar c) {
 // Space:                point.category == 'Zs'
 
 static const uint16_t kSpaceTable0Size = 9;
-static const uint16_t kSpaceTable0[9] = { 32, 160, 5760, 6158, 40960, 8202, 8239, 8287, 12288 }; // NOLINT
+static const int32_t kSpaceTable0[9] = { 32, 160, 5760, 6158, 1073750016, 8202, 8239, 8287, 12288 }; // NOLINT
 bool Space::Is(uchar c) {
   int chunk_index = c >> 15;
   switch (chunk_index) {
@@ -431,30 +444,16 @@ bool Space::Is(uchar c) {
   }
 }
 
-// Titlecase:            point.category == 'Lt'
-
-static const uint16_t kTitlecaseTable0Size = 13;
-static const uint16_t kTitlecaseTable0[13] = { 453, 456, 459, 498, 40840, 8079, 40856, 8095, 40872, 8111, 8124, 8140, 8188 }; // NOLINT
-bool Titlecase::Is(uchar c) {
-  int chunk_index = c >> 15;
-  switch (chunk_index) {
-    case 0: return LookupPredicate(kTitlecaseTable0,
-                                       kTitlecaseTable0Size,
-                                       c);
-    default: return false;
-  }
-}
-
 // Number:               point.category in ['Nd', 'Nl', 'No' ]
 
 static const uint16_t kNumberTable0Size = 86;
-static const uint16_t kNumberTable0[86] = { 32816, 57, 32946, 179, 185, 32956, 190, 34400, 1641, 34544, 1785, 34752, 1993, 35174, 2415, 35302, 2543, 35316, 2553, 35430, 2671, 35558, 2799, 35686, 2927, 35814, 3058, 35942, 3183, 36070, 3311, 36198, 3439, 36432, 3673, 36560, 3801, 36640, 3891, 36928, 4169, 37737, 4988, 38638, 5872, 38880, 6121, 38896, 6137, 38928, 6169, 39238, 6479, 39376, 6617, 39760, 7001, 8304, 41076, 8313, 41088, 8329, 41299, 8578, 42080, 9371, 42218, 9471, 42870, 10131, 11517, 12295, 45089, 12329, 45112, 12346, 45458, 12693, 45600, 12841, 45649, 12895, 45696, 12937, 45745, 12991 }; // NOLINT
+static const int32_t kNumberTable0[86] = { 1073741872, 57, 1073742002, 179, 185, 1073742012, 190, 1073743456, 1641, 1073743600, 1785, 1073743808, 1993, 1073744230, 2415, 1073744358, 2543, 1073744372, 2553, 1073744486, 2671, 1073744614, 2799, 1073744742, 2927, 1073744870, 3058, 1073744998, 3183, 1073745126, 3311, 1073745254, 3439, 1073745488, 3673, 1073745616, 3801, 1073745696, 3891, 1073745984, 4169, 1073746793, 4988, 1073747694, 5872, 1073747936, 6121, 1073747952, 6137, 1073747984, 6169, 1073748294, 6479, 1073748432, 6617, 1073748816, 7001, 8304, 1073750132, 8313, 1073750144, 8329, 1073750355, 8578, 1073751136, 9371, 1073751274, 9471, 1073751926, 10131, 11517, 12295, 1073754145, 12329, 1073754168, 12346, 1073754514, 12693, 1073754656, 12841, 1073754705, 12895, 1073754752, 12937, 1073754801, 12991 }; // NOLINT
 static const uint16_t kNumberTable1Size = 2;
-static const uint16_t kNumberTable1[2] = { 65296, 32537 }; // NOLINT
+static const int32_t kNumberTable1[2] = { 1073774352, 32537 }; // NOLINT
 static const uint16_t kNumberTable2Size = 19;
-static const uint16_t kNumberTable2[19] = { 33031, 307, 33088, 376, 394, 33568, 803, 833, 842, 33745, 981, 33952, 1193, 35094, 2329, 35392, 2631, 41984, 9314 }; // NOLINT
+static const int32_t kNumberTable2[19] = { 1073742087, 307, 1073742144, 376, 394, 1073742624, 803, 833, 842, 1073742801, 981, 1073743008, 1193, 1073744150, 2329, 1073744448, 2631, 1073751040, 9314 }; // NOLINT
 static const uint16_t kNumberTable3Size = 4;
-static const uint16_t kNumberTable3[4] = { 54112, 21361, 55246, 22527 }; // NOLINT
+static const int32_t kNumberTable3[4] = { 1073763168, 21361, 1073764302, 22527 }; // NOLINT
 bool Number::Is(uchar c) {
   int chunk_index = c >> 15;
   switch (chunk_index) {
@@ -474,68 +473,10 @@ bool Number::Is(uchar c) {
   }
 }
 
-// DecimalDigit:         point.category == 'Nd'
-
-static const uint16_t kDecimalDigitTable0Size = 44;
-static const uint16_t kDecimalDigitTable0[44] = { 32816, 57, 34400, 1641, 34544, 1785, 34752, 1993, 35174, 2415, 35302, 2543, 35430, 2671, 35558, 2799, 35686, 2927, 35814, 3055, 35942, 3183, 36070, 3311, 36198, 3439, 36432, 3673, 36560, 3801, 36640, 3881, 36928, 4169, 38880, 6121, 38928, 6169, 39238, 6479, 39376, 6617, 39760, 7001 }; // NOLINT
-static const uint16_t kDecimalDigitTable1Size = 2;
-static const uint16_t kDecimalDigitTable1[2] = { 65296, 32537 }; // NOLINT
-static const uint16_t kDecimalDigitTable2Size = 2;
-static const uint16_t kDecimalDigitTable2[2] = { 33952, 1193 }; // NOLINT
-static const uint16_t kDecimalDigitTable3Size = 2;
-static const uint16_t kDecimalDigitTable3[2] = { 55246, 22527 }; // NOLINT
-bool DecimalDigit::Is(uchar c) {
-  int chunk_index = c >> 15;
-  switch (chunk_index) {
-    case 0: return LookupPredicate(kDecimalDigitTable0,
-                                       kDecimalDigitTable0Size,
-                                       c);
-    case 1: return LookupPredicate(kDecimalDigitTable1,
-                                       kDecimalDigitTable1Size,
-                                       c);
-    case 2: return LookupPredicate(kDecimalDigitTable2,
-                                       kDecimalDigitTable2Size,
-                                       c);
-    case 3: return LookupPredicate(kDecimalDigitTable3,
-                                       kDecimalDigitTable3Size,
-                                       c);
-    default: return false;
-  }
-}
-
-// Ideographic:          'Id' in point.properties
-
-static const uint16_t kIdeographicTable0Size = 10;
-static const uint16_t kIdeographicTable0[10] = { 45062, 12295, 45089, 12329, 45112, 12346, 46080, 19893, 52736, 32767 }; // NOLINT
-static const uint16_t kIdeographicTable1Size = 6;
-static const uint16_t kIdeographicTable1[6] = { 32768, 8123, 63744, 31277, 64112, 31449 }; // NOLINT
-static const uint16_t kIdeographicTable4Size = 2;
-static const uint16_t kIdeographicTable4[2] = { 32768, 32767 }; // NOLINT
-static const uint16_t kIdeographicTable5Size = 4;
-static const uint16_t kIdeographicTable5[4] = { 32768, 9942, 63488, 31261 }; // NOLINT
-bool Ideographic::Is(uchar c) {
-  int chunk_index = c >> 15;
-  switch (chunk_index) {
-    case 0: return LookupPredicate(kIdeographicTable0,
-                                       kIdeographicTable0Size,
-                                       c);
-    case 1: return LookupPredicate(kIdeographicTable1,
-                                       kIdeographicTable1Size,
-                                       c);
-    case 4: return LookupPredicate(kIdeographicTable4,
-                                       kIdeographicTable4Size,
-                                       c);
-    case 5: return LookupPredicate(kIdeographicTable5,
-                                       kIdeographicTable5Size,
-                                       c);
-    default: return false;
-  }
-}
-
 // WhiteSpace:           'Ws' in point.properties
 
 static const uint16_t kWhiteSpaceTable0Size = 14;
-static const uint16_t kWhiteSpaceTable0[14] = { 32777, 13, 32, 133, 160, 5760, 6158, 40960, 8202, 41000, 8233, 8239, 8287, 12288 }; // NOLINT
+static const int32_t kWhiteSpaceTable0[14] = { 1073741833, 13, 32, 133, 160, 5760, 6158, 1073750016, 8202, 1073750056, 8233, 8239, 8287, 12288 }; // NOLINT
 bool WhiteSpace::Is(uchar c) {
   int chunk_index = c >> 15;
   switch (chunk_index) {
@@ -546,109 +487,10 @@ bool WhiteSpace::Is(uchar c) {
   }
 }
 
-// HexDigit:             'Hd' in point.properties
-
-static const uint16_t kHexDigitTable0Size = 6;
-static const uint16_t kHexDigitTable0[6] = { 32816, 57, 32833, 70, 32865, 102 }; // NOLINT
-static const uint16_t kHexDigitTable1Size = 6;
-static const uint16_t kHexDigitTable1[6] = { 65296, 32537, 65313, 32550, 65345, 32582 }; // NOLINT
-bool HexDigit::Is(uchar c) {
-  int chunk_index = c >> 15;
-  switch (chunk_index) {
-    case 0: return LookupPredicate(kHexDigitTable0,
-                                       kHexDigitTable0Size,
-                                       c);
-    case 1: return LookupPredicate(kHexDigitTable1,
-                                       kHexDigitTable1Size,
-                                       c);
-    default: return false;
-  }
-}
-
-// AsciiHexDigit:        'Ah' in point.properties
-
-static const uint16_t kAsciiHexDigitTable0Size = 6;
-static const uint16_t kAsciiHexDigitTable0[6] = { 32816, 57, 32833, 70, 32865, 102 }; // NOLINT
-bool AsciiHexDigit::Is(uchar c) {
-  int chunk_index = c >> 15;
-  switch (chunk_index) {
-    case 0: return LookupPredicate(kAsciiHexDigitTable0,
-                                       kAsciiHexDigitTable0Size,
-                                       c);
-    default: return false;
-  }
-}
-
-// BidiControl:          'Bc' in point.properties
-
-static const uint16_t kBidiControlTable0Size = 4;
-static const uint16_t kBidiControlTable0[4] = { 40974, 8207, 41002, 8238 }; // NOLINT
-bool BidiControl::Is(uchar c) {
-  int chunk_index = c >> 15;
-  switch (chunk_index) {
-    case 0: return LookupPredicate(kBidiControlTable0,
-                                       kBidiControlTable0Size,
-                                       c);
-    default: return false;
-  }
-}
-
-// JoinControl:          'Jc' in point.properties
-
-static const uint16_t kJoinControlTable0Size = 2;
-static const uint16_t kJoinControlTable0[2] = { 40972, 8205 }; // NOLINT
-bool JoinControl::Is(uchar c) {
-  int chunk_index = c >> 15;
-  switch (chunk_index) {
-    case 0: return LookupPredicate(kJoinControlTable0,
-                                       kJoinControlTable0Size,
-                                       c);
-    default: return false;
-  }
-}
-
-// Dash:                 'Dh' in point.properties
-
-static const uint16_t kDashTable0Size = 14;
-static const uint16_t kDashTable0[14] = { 45, 1418, 1470, 6150, 40976, 8213, 8275, 8315, 8331, 8722, 11799, 12316, 12336, 12448 }; // NOLINT
-static const uint16_t kDashTable1Size = 5;
-static const uint16_t kDashTable1[5] = { 65073, 32306, 32344, 32355, 32525 }; // NOLINT
-bool Dash::Is(uchar c) {
-  int chunk_index = c >> 15;
-  switch (chunk_index) {
-    case 0: return LookupPredicate(kDashTable0,
-                                       kDashTable0Size,
-                                       c);
-    case 1: return LookupPredicate(kDashTable1,
-                                       kDashTable1Size,
-                                       c);
-    default: return false;
-  }
-}
-
-// Hyphen:               'Hp' in point.properties
-
-static const uint16_t kHyphenTable0Size = 8;
-static const uint16_t kHyphenTable0[8] = { 45, 173, 1418, 6150, 40976, 8209, 11799, 12539 }; // NOLINT
-static const uint16_t kHyphenTable1Size = 3;
-static const uint16_t kHyphenTable1[3] = { 32355, 32525, 32613 }; // NOLINT
-bool Hyphen::Is(uchar c) {
-  int chunk_index = c >> 15;
-  switch (chunk_index) {
-    case 0: return LookupPredicate(kHyphenTable0,
-                                       kHyphenTable0Size,
-                                       c);
-    case 1: return LookupPredicate(kHyphenTable1,
-                                       kHyphenTable1Size,
-                                       c);
-    default: return false;
-  }
-}
-
 // LineTerminator:       'Lt' in point.properties
 
 static const uint16_t kLineTerminatorTable0Size = 4;
-static const uint16_t kLineTerminatorTable0[4] = { 10, 13, 41000, 8233 }; // NOLINT
+static const int32_t kLineTerminatorTable0[4] = { 10, 13, 1073750056, 8233 }; // NOLINT
 bool LineTerminator::Is(uchar c) {
   int chunk_index = c >> 15;
   switch (chunk_index) {
@@ -659,32 +501,18 @@ bool LineTerminator::Is(uchar c) {
   }
 }
 
-// RegExpSpecialChar:    'Rx' in point.properties
-
-static const uint16_t kRegExpSpecialCharTable0Size = 9;
-static const uint16_t kRegExpSpecialCharTable0[9] = { 36, 32808, 43, 46, 63, 32859, 94, 32891, 125 }; // NOLINT
-bool RegExpSpecialChar::Is(uchar c) {
-  int chunk_index = c >> 15;
-  switch (chunk_index) {
-    case 0: return LookupPredicate(kRegExpSpecialCharTable0,
-                                       kRegExpSpecialCharTable0Size,
-                                       c);
-    default: return false;
-  }
-}
-
 // CombiningMark:        point.category in ['Mn', 'Mc']
 
 static const uint16_t kCombiningMarkTable0Size = 214;
-static const uint16_t kCombiningMarkTable0[214] = { 33536, 879, 33923, 1158, 34193, 1469, 1471, 34241, 1474, 34244, 1477, 1479, 34320, 1557, 34379, 1630, 1648, 34518, 1756, 34527, 1764, 34535, 1768, 34538, 1773, 1809, 34608, 1866, 34726, 1968, 34795, 2035, 35073, 2307, 2364, 35134, 2381, 35153, 2388, 35170, 2403, 35201, 2435, 2492, 35262, 2500, 35271, 2504, 35275, 2509, 2519, 35298, 2531, 35329, 2563, 2620, 35390, 2626, 35399, 2632, 35403, 2637, 35440, 2673, 35457, 2691, 2748, 35518, 2757, 35527, 2761, 35531, 2765, 35554, 2787, 35585, 2819, 2876, 35646, 2883, 35655, 2888, 35659, 2893, 35670, 2903, 2946, 35774, 3010, 35782, 3016, 35786, 3021, 3031, 35841, 3075, 35902, 3140, 35910, 3144, 35914, 3149, 35925, 3158, 35970, 3203, 3260, 36030, 3268, 36038, 3272, 36042, 3277, 36053, 3286, 36066, 3299, 36098, 3331, 36158, 3395, 36166, 3400, 36170, 3405, 3415, 36226, 3459, 3530, 36303, 3540, 3542, 36312, 3551, 36338, 3571, 3633, 36404, 3642, 36423, 3662, 3761, 36532, 3769, 36539, 3772, 36552, 3789, 36632, 3865, 3893, 3895, 3897, 36670, 3903, 36721, 3972, 36742, 3975, 36752, 3991, 36761, 4028, 4038, 36908, 4146, 36918, 4153, 36950, 4185, 4959, 38674, 5908, 38706, 5940, 38738, 5971, 38770, 6003, 38838, 6099, 6109, 38923, 6157, 6313, 39200, 6443, 39216, 6459, 39344, 6592, 39368, 6601, 39447, 6683, 39680, 6916, 39732, 6980, 39787, 7027, 40384, 7626, 40446, 7679, 41168, 8412, 8417, 41189, 8431, 45098, 12335, 45209, 12442 }; // NOLINT
+static const int32_t kCombiningMarkTable0[214] = { 1073742592, 879, 1073742979, 1158, 1073743249, 1469, 1471, 1073743297, 1474, 1073743300, 1477, 1479, 1073743376, 1557, 1073743435, 1630, 1648, 1073743574, 1756, 1073743583, 1764, 1073743591, 1768, 1073743594, 1773, 1809, 1073743664, 1866, 1073743782, 1968, 1073743851, 2035, 1073744129, 2307, 2364, 1073744190, 2381, 1073744209, 2388, 1073744226, 2403, 1073744257, 2435, 2492, 1073744318, 2500, 1073744327, 2504, 1073744331, 2509, 2519, 1073744354, 2531, 1073744385, 2563, 2620, 1073744446, 2626, 1073744455, 2632, 1073744459, 2637, 1073744496, 2673, 1073744513, 2691, 2748, 1073744574, 2757, 1073744583, 2761, 1073744587, 2765, 1073744610, 2787, 1073744641, 2819, 2876, 1073744702, 2883, 1073744711, 2888, 1073744715, 2893, 1073744726, 2903, 2946, 1073744830, 3010, 1073744838, 3016, 1073744842, 3021, 3031, 1073744897, 3075, 1073744958, 3140, 1073744966, 3144, 1073744970, 3149, 1073744981, 3158, 1073745026, 3203, 3260, 1073745086, 3268, 1073745094, 3272, 1073745098, 3277, 1073745109, 3286, 1073745122, 3299, 1073745154, 3331, 1073745214, 3395, 1073745222, 3400, 1073745226, 3405, 3415, 1073745282, 3459, 3530, 1073745359, 3540, 3542, 1073745368, 3551, 1073745394, 3571, 3633, 1073745460, 3642, 1073745479, 3662, 3761, 1073745588, 3769, 1073745595, 3772, 1073745608, 3789, 1073745688, 3865, 3893, 3895, 3897, 1073745726, 3903, 1073745777, 3972, 1073745798, 3975, 1073745808, 3991, 1073745817, 4028, 4038, 1073745964, 4146, 1073745974, 4153, 1073746006, 4185, 4959, 1073747730, 5908, 1073747762, 5940, 1073747794, 5971, 1073747826, 6003, 1073747894, 6099, 6109, 1073747979, 6157, 6313, 1073748256, 6443, 1073748272, 6459, 1073748400, 6592, 1073748424, 6601, 1073748503, 6683, 1073748736, 6916, 1073748788, 6980, 1073748843, 7027, 1073749440, 7626, 1073749502, 7679, 1073750224, 8412, 8417, 1073750245, 8431, 1073754154, 12335, 1073754265, 12442 }; // NOLINT
 static const uint16_t kCombiningMarkTable1Size = 10;
-static const uint16_t kCombiningMarkTable1[10] = { 10242, 10246, 10251, 43043, 10279, 31518, 65024, 32271, 65056, 32291 }; // NOLINT
+static const int32_t kCombiningMarkTable1[10] = { 10242, 10246, 10251, 1073752099, 10279, 31518, 1073774080, 32271, 1073774112, 32291 }; // NOLINT
 static const uint16_t kCombiningMarkTable2Size = 9;
-static const uint16_t kCombiningMarkTable2[9] = { 35329, 2563, 35333, 2566, 35340, 2575, 35384, 2618, 2623 }; // NOLINT
+static const int32_t kCombiningMarkTable2[9] = { 1073744385, 2563, 1073744389, 2566, 1073744396, 2575, 1073744440, 2618, 2623 }; // NOLINT
 static const uint16_t kCombiningMarkTable3Size = 12;
-static const uint16_t kCombiningMarkTable3[12] = { 53605, 20841, 53613, 20850, 53627, 20866, 53637, 20875, 53674, 20909, 53826, 21060 }; // NOLINT
+static const int32_t kCombiningMarkTable3[12] = { 1073762661, 20841, 1073762669, 20850, 1073762683, 20866, 1073762693, 20875, 1073762730, 20909, 1073762882, 21060 }; // NOLINT
 static const uint16_t kCombiningMarkTable28Size = 2;
-static const uint16_t kCombiningMarkTable28[2] = { 33024, 495 }; // NOLINT
+static const int32_t kCombiningMarkTable28[2] = { 1073742080, 495 }; // NOLINT
 bool CombiningMark::Is(uchar c) {
   int chunk_index = c >> 15;
   switch (chunk_index) {
@@ -710,9 +538,9 @@ bool CombiningMark::Is(uchar c) {
 // ConnectorPunctuation: point.category == 'Pc'
 
 static const uint16_t kConnectorPunctuationTable0Size = 4;
-static const uint16_t kConnectorPunctuationTable0[4] = { 95, 41023, 8256, 8276 }; // NOLINT
+static const int32_t kConnectorPunctuationTable0[4] = { 95, 1073750079, 8256, 8276 }; // NOLINT
 static const uint16_t kConnectorPunctuationTable1Size = 5;
-static const uint16_t kConnectorPunctuationTable1[5] = { 65075, 32308, 65101, 32335, 32575 }; // NOLINT
+static const int32_t kConnectorPunctuationTable1[5] = { 1073774131, 32308, 1073774157, 32335, 32575 }; // NOLINT
 bool ConnectorPunctuation::Is(uchar c) {
   int chunk_index = c >> 15;
   switch (chunk_index) {
@@ -726,15 +554,15 @@ bool ConnectorPunctuation::Is(uchar c) {
   }
 }
 
-static const MultiCharacterSpecialCase kToLowercaseMultiStrings0[] = { {2, {105, 775}}, {0, {0}} }; // NOLINT
+static const MultiCharacterSpecialCase<3> kToLowercaseMultiStrings0[] = { {2, {105, 775}}, {0, {0}} }; // NOLINT
 static const uint16_t kToLowercaseTable0Size = 531;
-static const uint16_t kToLowercaseTable0[1062] = { 32833, 128, 90, 128, 32960, 128, 214, 128, 32984, 128, 222, 128, 256, 4, 258, 4, 260, 4, 262, 4, 264, 4, 266, 4, 268, 4, 270, 4, 272, 4, 274, 4, 276, 4, 278, 4, 280, 4, 282, 4, 284, 4, 286, 4, 288, 4, 290, 4, 292, 4, 294, 4, 296, 4, 298, 4, 300, 4, 302, 4, 304, 1, 306, 4, 308, 4, 310, 4, 313, 4, 315, 4, 317, 4, 319, 4, 321, 4, 323, 4, 325, 4, 327, 4, 330, 4, 332, 4, 334, 4, 336, 4, 338, 4, 340, 4, 342, 4, 344, 4, 346, 4, 348, 4, 350, 4, 352, 4, 354, 4, 356, 4, 358, 4, 360, 4, 362, 4, 364, 4, 366, 4, 368, 4, 370, 4, 372, 4, 374, 4, 376, static_cast<uint16_t>(-484), 377, 4, 379, 4, 381, 4, 385, 840, 386, 4, 388, 4, 390, 824, 391, 4, 33161, 820, 394, 820, 395, 4, 398, 316, 399, 808, 400, 812, 401, 4, 403, 820, 404, 828, 406, 844, 407, 836, 408, 4, 412, 844, 413, 852, 415, 856, 416, 4, 418, 4, 420, 4, 422, 872, 423, 4, 425, 872, 428, 4, 430, 872, 431, 4, 33201, 868, 434, 868, 435, 4, 437, 4, 439, 876, 440, 4, 444, 4, 452, 8, 453, 4, 455, 8, 456, 4, 458, 8, 459, 4, 461, 4, 463, 4, 465, 4, 467, 4, 469, 4, 471, 4, 473, 4, 475, 4, 478, 4, 480, 4, 482, 4, 484, 4, 486, 4, 488, 4, 490, 4, 492, 4, 494, 4, 497, 8, 498, 4, 500, 4, 502, static_cast<uint16_t>(-388), 503, static_cast<uint16_t>(-224), 504, 4, 506, 4, 508, 4, 510, 4, 512, 4, 514, 4, 516, 4, 518, 4, 520, 4, 522, 4, 524, 4, 526, 4, 528, 4, 530, 4, 532, 4, 534, 4, 536, 4, 538, 4, 540, 4, 542, 4, 544, static_cast<uint16_t>(-520), 546, 4, 548, 4, 550, 4, 552, 4, 554, 4, 556, 4, 558, 4, 560, 4, 562, 4, 570, 43180, 571, 4, 573, static_cast<uint16_t>(-652), 574, 43168, 577, 4, 579, static_cast<uint16_t>(-780), 580, 276, 581, 284, 582, 4, 584, 4, 586, 4, 588, 4, 590, 4, 902, 152, 33672, 148, 906, 148, 908, 256, 33678, 252, 911, 252, 33681, 128, 929, 128, 33699, 6, 939, 128, 984, 4, 986, 4, 988, 4, 990, 4, 992, 4, 994, 4, 996, 4, 998, 4, 1000, 4, 1002, 4, 1004, 4, 1006, 4, 1012, static_cast<uint16_t>(-240), 1015, 4, 1017, static_cast<uint16_t>(-28), 1018, 4, 33789, static_cast<uint16_t>(-520), 1023, static_cast<uint16_t>(-520), 33792, 320, 1039, 320, 33808, 128, 1071, 128, 1120, 4, 1122, 4, 1124, 4, 1126, 4, 1128, 4, 1130, 4, 1132, 4, 1134, 4, 1136, 4, 1138, 4, 1140, 4, 1142, 4, 1144, 4, 1146, 4, 1148, 4, 1150, 4, 1152, 4, 1162, 4, 1164, 4, 1166, 4, 1168, 4, 1170, 4, 1172, 4, 1174, 4, 1176, 4, 1178, 4, 1180, 4, 1182, 4, 1184, 4, 1186, 4, 1188, 4, 1190, 4, 1192, 4, 1194, 4, 1196, 4, 1198, 4, 1200, 4, 1202, 4, 1204, 4, 1206, 4, 1208, 4, 1210, 4, 1212, 4, 1214, 4, 1216, 60, 1217, 4, 1219, 4, 1221, 4, 1223, 4, 1225, 4, 1227, 4, 1229, 4, 1232, 4, 1234, 4, 1236, 4, 1238, 4, 1240, 4, 1242, 4, 1244, 4, 1246, 4, 1248, 4, 1250, 4, 1252, 4, 1254, 4, 1256, 4, 1258, 4, 1260, 4, 1262, 4, 1264, 4, 1266, 4, 1268, 4, 1270, 4, 1272, 4, 1274, 4, 1276, 4, 1278, 4, 1280, 4, 1282, 4, 1284, 4, 1286, 4, 1288, 4, 1290, 4, 1292, 4, 1294, 4, 1296, 4, 1298, 4, 34097, 192, 1366, 192, 37024, 29056, 4293, 29056, 7680, 4, 7682, 4, 7684, 4, 7686, 4, 7688, 4, 7690, 4, 7692, 4, 7694, 4, 7696, 4, 7698, 4, 7700, 4, 7702, 4, 7704, 4, 7706, 4, 7708, 4, 7710, 4, 7712, 4, 7714, 4, 7716, 4, 7718, 4, 7720, 4, 7722, 4, 7724, 4, 7726, 4, 7728, 4, 7730, 4, 7732, 4, 7734, 4, 7736, 4, 7738, 4, 7740, 4, 7742, 4, 7744, 4, 7746, 4, 7748, 4, 7750, 4, 7752, 4, 7754, 4, 7756, 4, 7758, 4, 7760, 4, 7762, 4, 7764, 4, 7766, 4, 7768, 4, 7770, 4, 7772, 4, 7774, 4, 7776, 4, 7778, 4, 7780, 4, 7782, 4, 7784, 4, 7786, 4, 7788, 4, 7790, 4, 7792, 4, 7794, 4, 7796, 4, 7798, 4, 7800, 4, 7802, 4, 7804, 4, 7806, 4, 7808, 4, 7810, 4, 7812, 4, 7814, 4, 7816, 4, 7818, 4, 7820, 4, 7822, 4, 7824, 4, 7826, 4, 7828, 4, 7840, 4, 7842, 4, 7844, 4, 7846, 4, 7848, 4, 7850, 4, 7852, 4, 7854, 4, 7856, 4, 7858, 4, 7860, 4, 7862, 4, 7864, 4, 7866, 4, 7868, 4, 7870, 4, 7872, 4, 7874, 4, 7876, 4, 7878, 4, 7880, 4, 7882, 4, 7884, 4, 7886, 4, 7888, 4, 7890, 4, 7892, 4, 7894, 4, 7896, 4, 7898, 4, 7900, 4, 7902, 4, 7904, 4, 7906, 4, 7908, 4, 7910, 4, 7912, 4, 7914, 4, 7916, 4, 7918, 4, 7920, 4, 7922, 4, 7924, 4, 7926, 4, 7928, 4, 40712, static_cast<uint16_t>(-32), 7951, static_cast<uint16_t>(-32), 40728, static_cast<uint16_t>(-32), 7965, static_cast<uint16_t>(-32), 40744, static_cast<uint16_t>(-32), 7983, static_cast<uint16_t>(-32), 40760, static_cast<uint16_t>(-32), 7999, static_cast<uint16_t>(-32), 40776, static_cast<uint16_t>(-32), 8013, static_cast<uint16_t>(-32), 8025, static_cast<uint16_t>(-32), 8027, static_cast<uint16_t>(-32), 8029, static_cast<uint16_t>(-32), 8031, static_cast<uint16_t>(-32), 40808, static_cast<uint16_t>(-32), 8047, static_cast<uint16_t>(-32), 40840, static_cast<uint16_t>(-32), 8079, static_cast<uint16_t>(-32), 40856, static_cast<uint16_t>(-32), 8095, static_cast<uint16_t>(-32), 40872, static_cast<uint16_t>(-32), 8111, static_cast<uint16_t>(-32), 40888, static_cast<uint16_t>(-32), 8121, static_cast<uint16_t>(-32), 40890, static_cast<uint16_t>(-296), 8123, static_cast<uint16_t>(-296), 8124, static_cast<uint16_t>(-36), 40904, static_cast<uint16_t>(-344), 8139, static_cast<uint16_t>(-344), 8140, static_cast<uint16_t>(-36), 40920, static_cast<uint16_t>(-32), 8153, static_cast<uint16_t>(-32), 40922, static_cast<uint16_t>(-400), 8155, static_cast<uint16_t>(-400), 40936, static_cast<uint16_t>(-32), 8169, static_cast<uint16_t>(-32), 40938, static_cast<uint16_t>(-448), 8171, static_cast<uint16_t>(-448), 8172, static_cast<uint16_t>(-28), 40952, static_cast<uint16_t>(-512), 8185, static_cast<uint16_t>(-512), 40954, static_cast<uint16_t>(-504), 8187, static_cast<uint16_t>(-504), 8188, static_cast<uint16_t>(-36), 8486, static_cast<uint16_t>(-30068), 8490, static_cast<uint16_t>(-33532), 8491, static_cast<uint16_t>(-33048), 8498, 112, 41312, 64, 8559, 64, 8579, 4, 42166, 104, 9423, 104, 44032, 192, 11310, 192, 11360, 4, 11362, static_cast<uint16_t>(-42972), 11363, static_cast<uint16_t>(-15256), 11364, static_cast<uint16_t>(-42908), 11367, 4, 11369, 4, 11371, 4, 11381, 4, 11392, 4, 11394, 4, 11396, 4, 11398, 4, 11400, 4, 11402, 4, 11404, 4, 11406, 4, 11408, 4, 11410, 4, 11412, 4, 11414, 4, 11416, 4, 11418, 4, 11420, 4, 11422, 4, 11424, 4, 11426, 4, 11428, 4, 11430, 4, 11432, 4, 11434, 4, 11436, 4, 11438, 4, 11440, 4, 11442, 4, 11444, 4, 11446, 4, 11448, 4, 11450, 4, 11452, 4, 11454, 4, 11456, 4, 11458, 4, 11460, 4, 11462, 4, 11464, 4, 11466, 4, 11468, 4, 11470, 4, 11472, 4, 11474, 4, 11476, 4, 11478, 4, 11480, 4, 11482, 4, 11484, 4, 11486, 4, 11488, 4, 11490, 4 }; // NOLINT
-static const MultiCharacterSpecialCase kToLowercaseMultiStrings1[] = { {0, {0}} }; // NOLINT
+static const int32_t kToLowercaseTable0[1062] = { 1073741889, 128, 90, 128, 1073742016, 128, 214, 128, 1073742040, 128, 222, 128, 256, 4, 258, 4, 260, 4, 262, 4, 264, 4, 266, 4, 268, 4, 270, 4, 272, 4, 274, 4, 276, 4, 278, 4, 280, 4, 282, 4, 284, 4, 286, 4, 288, 4, 290, 4, 292, 4, 294, 4, 296, 4, 298, 4, 300, 4, 302, 4, 304, 1, 306, 4, 308, 4, 310, 4, 313, 4, 315, 4, 317, 4, 319, 4, 321, 4, 323, 4, 325, 4, 327, 4, 330, 4, 332, 4, 334, 4, 336, 4, 338, 4, 340, 4, 342, 4, 344, 4, 346, 4, 348, 4, 350, 4, 352, 4, 354, 4, 356, 4, 358, 4, 360, 4, 362, 4, 364, 4, 366, 4, 368, 4, 370, 4, 372, 4, 374, 4, 376, -484, 377, 4, 379, 4, 381, 4, 385, 840, 386, 4, 388, 4, 390, 824, 391, 4, 1073742217, 820, 394, 820, 395, 4, 398, 316, 399, 808, 400, 812, 401, 4, 403, 820, 404, 828, 406, 844, 407, 836, 408, 4, 412, 844, 413, 852, 415, 856, 416, 4, 418, 4, 420, 4, 422, 872, 423, 4, 425, 872, 428, 4, 430, 872, 431, 4, 1073742257, 868, 434, 868, 435, 4, 437, 4, 439, 876, 440, 4, 444, 4, 452, 8, 453, 4, 455, 8, 456, 4, 458, 8, 459, 4, 461, 4, 463, 4, 465, 4, 467, 4, 469, 4, 471, 4, 473, 4, 475, 4, 478, 4, 480, 4, 482, 4, 484, 4, 486, 4, 488, 4, 490, 4, 492, 4, 494, 4, 497, 8, 498, 4, 500, 4, 502, -388, 503, -224, 504, 4, 506, 4, 508, 4, 510, 4, 512, 4, 514, 4, 516, 4, 518, 4, 520, 4, 522, 4, 524, 4, 526, 4, 528, 4, 530, 4, 532, 4, 534, 4, 536, 4, 538, 4, 540, 4, 542, 4, 544, -520, 546, 4, 548, 4, 550, 4, 552, 4, 554, 4, 556, 4, 558, 4, 560, 4, 562, 4, 570, 43180, 571, 4, 573, -652, 574, 43168, 577, 4, 579, -780, 580, 276, 581, 284, 582, 4, 584, 4, 586, 4, 588, 4, 590, 4, 902, 152, 1073742728, 148, 906, 148, 908, 256, 1073742734, 252, 911, 252, 1073742737, 128, 929, 128, 1073742755, 6, 939, 128, 984, 4, 986, 4, 988, 4, 990, 4, 992, 4, 994, 4, 996, 4, 998, 4, 1000, 4, 1002, 4, 1004, 4, 1006, 4, 1012, -240, 1015, 4, 1017, -28, 1018, 4, 1073742845, -520, 1023, -520, 1073742848, 320, 1039, 320, 1073742864, 128, 1071, 128, 1120, 4, 1122, 4, 1124, 4, 1126, 4, 1128, 4, 1130, 4, 1132, 4, 1134, 4, 1136, 4, 1138, 4, 1140, 4, 1142, 4, 1144, 4, 1146, 4, 1148, 4, 1150, 4, 1152, 4, 1162, 4, 1164, 4, 1166, 4, 1168, 4, 1170, 4, 1172, 4, 1174, 4, 1176, 4, 1178, 4, 1180, 4, 1182, 4, 1184, 4, 1186, 4, 1188, 4, 1190, 4, 1192, 4, 1194, 4, 1196, 4, 1198, 4, 1200, 4, 1202, 4, 1204, 4, 1206, 4, 1208, 4, 1210, 4, 1212, 4, 1214, 4, 1216, 60, 1217, 4, 1219, 4, 1221, 4, 1223, 4, 1225, 4, 1227, 4, 1229, 4, 1232, 4, 1234, 4, 1236, 4, 1238, 4, 1240, 4, 1242, 4, 1244, 4, 1246, 4, 1248, 4, 1250, 4, 1252, 4, 1254, 4, 1256, 4, 1258, 4, 1260, 4, 1262, 4, 1264, 4, 1266, 4, 1268, 4, 1270, 4, 1272, 4, 1274, 4, 1276, 4, 1278, 4, 1280, 4, 1282, 4, 1284, 4, 1286, 4, 1288, 4, 1290, 4, 1292, 4, 1294, 4, 1296, 4, 1298, 4, 1073743153, 192, 1366, 192, 1073746080, 29056, 4293, 29056, 7680, 4, 7682, 4, 7684, 4, 7686, 4, 7688, 4, 7690, 4, 7692, 4, 7694, 4, 7696, 4, 7698, 4, 7700, 4, 7702, 4, 7704, 4, 7706, 4, 7708, 4, 7710, 4, 7712, 4, 7714, 4, 7716, 4, 7718, 4, 7720, 4, 7722, 4, 7724, 4, 7726, 4, 7728, 4, 7730, 4, 7732, 4, 7734, 4, 7736, 4, 7738, 4, 7740, 4, 7742, 4, 7744, 4, 7746, 4, 7748, 4, 7750, 4, 7752, 4, 7754, 4, 7756, 4, 7758, 4, 7760, 4, 7762, 4, 7764, 4, 7766, 4, 7768, 4, 7770, 4, 7772, 4, 7774, 4, 7776, 4, 7778, 4, 7780, 4, 7782, 4, 7784, 4, 7786, 4, 7788, 4, 7790, 4, 7792, 4, 7794, 4, 7796, 4, 7798, 4, 7800, 4, 7802, 4, 7804, 4, 7806, 4, 7808, 4, 7810, 4, 7812, 4, 7814, 4, 7816, 4, 7818, 4, 7820, 4, 7822, 4, 7824, 4, 7826, 4, 7828, 4, 7840, 4, 7842, 4, 7844, 4, 7846, 4, 7848, 4, 7850, 4, 7852, 4, 7854, 4, 7856, 4, 7858, 4, 7860, 4, 7862, 4, 7864, 4, 7866, 4, 7868, 4, 7870, 4, 7872, 4, 7874, 4, 7876, 4, 7878, 4, 7880, 4, 7882, 4, 7884, 4, 7886, 4, 7888, 4, 7890, 4, 7892, 4, 7894, 4, 7896, 4, 7898, 4, 7900, 4, 7902, 4, 7904, 4, 7906, 4, 7908, 4, 7910, 4, 7912, 4, 7914, 4, 7916, 4, 7918, 4, 7920, 4, 7922, 4, 7924, 4, 7926, 4, 7928, 4, 1073749768, -32, 7951, -32, 1073749784, -32, 7965, -32, 1073749800, -32, 7983, -32, 1073749816, -32, 7999, -32, 1073749832, -32, 8013, -32, 8025, -32, 8027, -32, 8029, -32, 8031, -32, 1073749864, -32, 8047, -32, 1073749896, -32, 8079, -32, 1073749912, -32, 8095, -32, 1073749928, -32, 8111, -32, 1073749944, -32, 8121, -32, 1073749946, -296, 8123, -296, 8124, -36, 1073749960, -344, 8139, -344, 8140, -36, 1073749976, -32, 8153, -32, 1073749978, -400, 8155, -400, 1073749992, -32, 8169, -32, 1073749994, -448, 8171, -448, 8172, -28, 1073750008, -512, 8185, -512, 1073750010, -504, 8187, -504, 8188, -36, 8486, -30068, 8490, -33532, 8491, -33048, 8498, 112, 1073750368, 64, 8559, 64, 8579, 4, 1073751222, 104, 9423, 104, 1073753088, 192, 11310, 192, 11360, 4, 11362, -42972, 11363, -15256, 11364, -42908, 11367, 4, 11369, 4, 11371, 4, 11381, 4, 11392, 4, 11394, 4, 11396, 4, 11398, 4, 11400, 4, 11402, 4, 11404, 4, 11406, 4, 11408, 4, 11410, 4, 11412, 4, 11414, 4, 11416, 4, 11418, 4, 11420, 4, 11422, 4, 11424, 4, 11426, 4, 11428, 4, 11430, 4, 11432, 4, 11434, 4, 11436, 4, 11438, 4, 11440, 4, 11442, 4, 11444, 4, 11446, 4, 11448, 4, 11450, 4, 11452, 4, 11454, 4, 11456, 4, 11458, 4, 11460, 4, 11462, 4, 11464, 4, 11466, 4, 11468, 4, 11470, 4, 11472, 4, 11474, 4, 11476, 4, 11478, 4, 11480, 4, 11482, 4, 11484, 4, 11486, 4, 11488, 4, 11490, 4 }; // NOLINT
+static const MultiCharacterSpecialCase<3> kToLowercaseMultiStrings1[] = { {0, {0}} }; // NOLINT
 static const uint16_t kToLowercaseTable1Size = 2;
-static const uint16_t kToLowercaseTable1[4] = { 65313, 128, 32570, 128 }; // NOLINT
-static const MultiCharacterSpecialCase kToLowercaseMultiStrings2[] = { {0, {0}} }; // NOLINT
+static const int32_t kToLowercaseTable1[4] = { 1073774369, 128, 32570, 128 }; // NOLINT
+static const MultiCharacterSpecialCase<3> kToLowercaseMultiStrings2[] = { {0, {0}} }; // NOLINT
 static const uint16_t kToLowercaseTable2Size = 2;
-static const uint16_t kToLowercaseTable2[4] = { 33792, 160, 1063, 160 }; // NOLINT
+static const int32_t kToLowercaseTable2[4] = { 1073742848, 160, 1063, 160 }; // NOLINT
 int ToLowercase::Convert(uchar c,
                       uchar n,
                       uchar* result,
@@ -766,15 +594,15 @@ int ToLowercase::Convert(uchar c,
   }
 }
 
-static const MultiCharacterSpecialCase kToUppercaseMultiStrings0[] = { {2, {83, 83}}, {2, {700, 78}}, {2, {74, 780}}, {3, {921, 776, 769}}, {3, {933, 776, 769}}, {2, {1333, 1362}}, {2, {72, 817}}, {2, {84, 776}}, {2, {87, 778}}, {2, {89, 778}}, {2, {65, 702}}, {2, {933, 787}}, {3, {933, 787, 768}}, {3, {933, 787, 769}}, {3, {933, 787, 834}}, {2, {7944, 921}}, {2, {7945, 921}}, {2, {7946, 921}}, {2, {7947, 921}}, {2, {7948, 921}}, {2, {7949, 921}}, {2, {7950, 921}}, {2, {7951, 921}}, {2, {7944, 921}}, {2, {7945, 921}}, {2, {7946, 921}}, {2, {7947, 921}}, {2, {7948, 921}}, {2, {7949, 921}}, {2, {7950, 921}}, {2, {7951, 921}}, {2, {7976, 921}}, {2, {7977, 921}}, {2, {7978, 921}}, {2, {7979, 921}}, {2, {7980, 921}}, {2, {7981, 921}}, {2, {7982, 921}}, {2, {7983, 921}}, {2, {7976, 921}}, {2, {7977, 921}}, {2, {7978, 921}}, {2, {7979, 921}}, {2, {7980, 921}}, {2, {7981, 921}}, {2, {7982, 921}}, {2, {7983, 921}}, {2, {8040, 921}}, {2, {8041, 921}}, {2, {8042, 921}}, {2, {8043, 921}}, {2, {8044, 921}}, {2, {8045, 921}}, {2, {8046, 921}}, {2, {8047, 921}}, {2, {8040, 921}}, {2, {8041, 921}}, {2, {8042, 921}}, {2, {8043, 921}}, {2, {8044, 921}}, {2, {8045, 921}}, {2, {8046, 921}}, {2, {8047, 921}}, {2, {8122, 921}}, {2, {913, 921}}, {2, {902, 921}}, {2, {913, 834}}, {3, {913, 834, 921}}, {2, {913, 921}}, {2, {8138, 921}}, {2, {919, 921}}, {2, {905, 921}}, {2, {919, 834}}, {3, {919, 834, 921}}, {2, {919, 921}}, {3, {921, 776, 768}}, {3, {921, 776, 769}}, {2, {921, 834}}, {3, {921, 776, 834}}, {3, {933, 776, 768}}, {3, {933, 776, 769}}, {2, {929, 787}}, {2, {933, 834}}, {3, {933, 776, 834}}, {2, {8186, 921}}, {2, {937, 921}}, {2, {911, 921}}, {2, {937, 834}}, {3, {937, 834, 921}}, {2, {937, 921}}, {0, {0}} }; // NOLINT
+static const MultiCharacterSpecialCase<3> kToUppercaseMultiStrings0[] = { {2, {83, 83}}, {2, {700, 78}}, {2, {74, 780}}, {3, {921, 776, 769}}, {3, {933, 776, 769}}, {2, {1333, 1362}}, {2, {72, 817}}, {2, {84, 776}}, {2, {87, 778}}, {2, {89, 778}}, {2, {65, 702}}, {2, {933, 787}}, {3, {933, 787, 768}}, {3, {933, 787, 769}}, {3, {933, 787, 834}}, {2, {7944, 921}}, {2, {7945, 921}}, {2, {7946, 921}}, {2, {7947, 921}}, {2, {7948, 921}}, {2, {7949, 921}}, {2, {7950, 921}}, {2, {7951, 921}}, {2, {7944, 921}}, {2, {7945, 921}}, {2, {7946, 921}}, {2, {7947, 921}}, {2, {7948, 921}}, {2, {7949, 921}}, {2, {7950, 921}}, {2, {7951, 921}}, {2, {7976, 921}}, {2, {7977, 921}}, {2, {7978, 921}}, {2, {7979, 921}}, {2, {7980, 921}}, {2, {7981, 921}}, {2, {7982, 921}}, {2, {7983, 921}}, {2, {7976, 921}}, {2, {7977, 921}}, {2, {7978, 921}}, {2, {7979, 921}}, {2, {7980, 921}}, {2, {7981, 921}}, {2, {7982, 921}}, {2, {7983, 921}}, {2, {8040, 921}}, {2, {8041, 921}}, {2, {8042, 921}}, {2, {8043, 921}}, {2, {8044, 921}}, {2, {8045, 921}}, {2, {8046, 921}}, {2, {8047, 921}}, {2, {8040, 921}}, {2, {8041, 921}}, {2, {8042, 921}}, {2, {8043, 921}}, {2, {8044, 921}}, {2, {8045, 921}}, {2, {8046, 921}}, {2, {8047, 921}}, {2, {8122, 921}}, {2, {913, 921}}, {2, {902, 921}}, {2, {913, 834}}, {3, {913, 834, 921}}, {2, {913, 921}}, {2, {8138, 921}}, {2, {919, 921}}, {2, {905, 921}}, {2, {919, 834}}, {3, {919, 834, 921}}, {2, {919, 921}}, {3, {921, 776, 768}}, {3, {921, 776, 769}}, {2, {921, 834}}, {3, {921, 776, 834}}, {3, {933, 776, 768}}, {3, {933, 776, 769}}, {2, {929, 787}}, {2, {933, 834}}, {3, {933, 776, 834}}, {2, {8186, 921}}, {2, {937, 921}}, {2, {911, 921}}, {2, {937, 834}}, {3, {937, 834, 921}}, {2, {937, 921}}, {0, {0}} }; // NOLINT
 static const uint16_t kToUppercaseTable0Size = 621;
-static const uint16_t kToUppercaseTable0[1242] = { 32865, static_cast<uint16_t>(-128), 122, static_cast<uint16_t>(-128), 181, 2972, 223, 1, 32992, static_cast<uint16_t>(-128), 246, static_cast<uint16_t>(-128), 33016, static_cast<uint16_t>(-128), 254, static_cast<uint16_t>(-128), 255, 484, 257, static_cast<uint16_t>(-4), 259, static_cast<uint16_t>(-4), 261, static_cast<uint16_t>(-4), 263, static_cast<uint16_t>(-4), 265, static_cast<uint16_t>(-4), 267, static_cast<uint16_t>(-4), 269, static_cast<uint16_t>(-4), 271, static_cast<uint16_t>(-4), 273, static_cast<uint16_t>(-4), 275, static_cast<uint16_t>(-4), 277, static_cast<uint16_t>(-4), 279, static_cast<uint16_t>(-4), 281, static_cast<uint16_t>(-4), 283, static_cast<uint16_t>(-4), 285, static_cast<uint16_t>(-4), 287, static_cast<uint16_t>(-4), 289, static_cast<uint16_t>(-4), 291, static_cast<uint16_t>(-4), 293, static_cast<uint16_t>(-4), 295, static_cast<uint16_t>(-4), 297, static_cast<uint16_t>(-4), 299, static_cast<uint16_t>(-4), 301, static_cast<uint16_t>(-4), 303, static_cast<uint16_t>(-4), 305, static_cast<uint16_t>(-928), 307, static_cast<uint16_t>(-4), 309, static_cast<uint16_t>(-4), 311, static_cast<uint16_t>(-4), 314, static_cast<uint16_t>(-4), 316, static_cast<uint16_t>(-4), 318, static_cast<uint16_t>(-4), 320, static_cast<uint16_t>(-4), 322, static_cast<uint16_t>(-4), 324, static_cast<uint16_t>(-4), 326, static_cast<uint16_t>(-4), 328, static_cast<uint16_t>(-4), 329, 5, 331, static_cast<uint16_t>(-4), 333, static_cast<uint16_t>(-4), 335, static_cast<uint16_t>(-4), 337, static_cast<uint16_t>(-4), 339, static_cast<uint16_t>(-4), 341, static_cast<uint16_t>(-4), 343, static_cast<uint16_t>(-4), 345, static_cast<uint16_t>(-4), 347, static_cast<uint16_t>(-4), 349, static_cast<uint16_t>(-4), 351, static_cast<uint16_t>(-4), 353, static_cast<uint16_t>(-4), 355, static_cast<uint16_t>(-4), 357, static_cast<uint16_t>(-4), 359, static_cast<uint16_t>(-4), 361, static_cast<uint16_t>(-4), 363, static_cast<uint16_t>(-4), 365, static_cast<uint16_t>(-4), 367, static_cast<uint16_t>(-4), 369, static_cast<uint16_t>(-4), 371, static_cast<uint16_t>(-4), 373, static_cast<uint16_t>(-4), 375, static_cast<uint16_t>(-4), 378, static_cast<uint16_t>(-4), 380, static_cast<uint16_t>(-4), 382, static_cast<uint16_t>(-4), 383, static_cast<uint16_t>(-1200), 384, 780, 387, static_cast<uint16_t>(-4), 389, static_cast<uint16_t>(-4), 392, static_cast<uint16_t>(-4), 396, static_cast<uint16_t>(-4), 402, static_cast<uint16_t>(-4), 405, 388, 409, static_cast<uint16_t>(-4), 410, 652, 414, 520, 417, static_cast<uint16_t>(-4), 419, static_cast<uint16_t>(-4), 421, static_cast<uint16_t>(-4), 424, static_cast<uint16_t>(-4), 429, static_cast<uint16_t>(-4), 432, static_cast<uint16_t>(-4), 436, static_cast<uint16_t>(-4), 438, static_cast<uint16_t>(-4), 441, static_cast<uint16_t>(-4), 445, static_cast<uint16_t>(-4), 447, 224, 453, static_cast<uint16_t>(-4), 454, static_cast<uint16_t>(-8), 456, static_cast<uint16_t>(-4), 457, static_cast<uint16_t>(-8), 459, static_cast<uint16_t>(-4), 460, static_cast<uint16_t>(-8), 462, static_cast<uint16_t>(-4), 464, static_cast<uint16_t>(-4), 466, static_cast<uint16_t>(-4), 468, static_cast<uint16_t>(-4), 470, static_cast<uint16_t>(-4), 472, static_cast<uint16_t>(-4), 474, static_cast<uint16_t>(-4), 476, static_cast<uint16_t>(-4), 477, static_cast<uint16_t>(-316), 479, static_cast<uint16_t>(-4), 481, static_cast<uint16_t>(-4), 483, static_cast<uint16_t>(-4), 485, static_cast<uint16_t>(-4), 487, static_cast<uint16_t>(-4), 489, static_cast<uint16_t>(-4), 491, static_cast<uint16_t>(-4), 493, static_cast<uint16_t>(-4), 495, static_cast<uint16_t>(-4), 496, 9, 498, static_cast<uint16_t>(-4), 499, static_cast<uint16_t>(-8), 501, static_cast<uint16_t>(-4), 505, static_cast<uint16_t>(-4), 507, static_cast<uint16_t>(-4), 509, static_cast<uint16_t>(-4), 511, static_cast<uint16_t>(-4), 513, static_cast<uint16_t>(-4), 515, static_cast<uint16_t>(-4), 517, static_cast<uint16_t>(-4), 519, static_cast<uint16_t>(-4), 521, static_cast<uint16_t>(-4), 523, static_cast<uint16_t>(-4), 525, static_cast<uint16_t>(-4), 527, static_cast<uint16_t>(-4), 529, static_cast<uint16_t>(-4), 531, static_cast<uint16_t>(-4), 533, static_cast<uint16_t>(-4), 535, static_cast<uint16_t>(-4), 537, static_cast<uint16_t>(-4), 539, static_cast<uint16_t>(-4), 541, static_cast<uint16_t>(-4), 543, static_cast<uint16_t>(-4), 547, static_cast<uint16_t>(-4), 549, static_cast<uint16_t>(-4), 551, static_cast<uint16_t>(-4), 553, static_cast<uint16_t>(-4), 555, static_cast<uint16_t>(-4), 557, static_cast<uint16_t>(-4), 559, static_cast<uint16_t>(-4), 561, static_cast<uint16_t>(-4), 563, static_cast<uint16_t>(-4), 572, static_cast<uint16_t>(-4), 578, static_cast<uint16_t>(-4), 583, static_cast<uint16_t>(-4), 585, static_cast<uint16_t>(-4), 587, static_cast<uint16_t>(-4), 589, static_cast<uint16_t>(-4), 591, static_cast<uint16_t>(-4), 595, static_cast<uint16_t>(-840), 596, static_cast<uint16_t>(-824), 33366, static_cast<uint16_t>(-820), 599, static_cast<uint16_t>(-820), 601, static_cast<uint16_t>(-808), 603, static_cast<uint16_t>(-812), 608, static_cast<uint16_t>(-820), 611, static_cast<uint16_t>(-828), 616, static_cast<uint16_t>(-836), 617, static_cast<uint16_t>(-844), 619, 42972, 623, static_cast<uint16_t>(-844), 626, static_cast<uint16_t>(-852), 629, static_cast<uint16_t>(-856), 637, 42908, 640, static_cast<uint16_t>(-872), 643, static_cast<uint16_t>(-872), 648, static_cast<uint16_t>(-872), 649, static_cast<uint16_t>(-276), 33418, static_cast<uint16_t>(-868), 651, static_cast<uint16_t>(-868), 652, static_cast<uint16_t>(-284), 658, static_cast<uint16_t>(-876), 837, 336, 33659, 520, 893, 520, 912, 13, 940, static_cast<uint16_t>(-152), 33709, static_cast<uint16_t>(-148), 943, static_cast<uint16_t>(-148), 944, 17, 33713, static_cast<uint16_t>(-128), 961, static_cast<uint16_t>(-128), 962, static_cast<uint16_t>(-124), 33731, static_cast<uint16_t>(-128), 971, static_cast<uint16_t>(-128), 972, static_cast<uint16_t>(-256), 33741, static_cast<uint16_t>(-252), 974, static_cast<uint16_t>(-252), 976, static_cast<uint16_t>(-248), 977, static_cast<uint16_t>(-228), 981, static_cast<uint16_t>(-188), 982, static_cast<uint16_t>(-216), 985, static_cast<uint16_t>(-4), 987, static_cast<uint16_t>(-4), 989, static_cast<uint16_t>(-4), 991, static_cast<uint16_t>(-4), 993, static_cast<uint16_t>(-4), 995, static_cast<uint16_t>(-4), 997, static_cast<uint16_t>(-4), 999, static_cast<uint16_t>(-4), 1001, static_cast<uint16_t>(-4), 1003, static_cast<uint16_t>(-4), 1005, static_cast<uint16_t>(-4), 1007, static_cast<uint16_t>(-4), 1008, static_cast<uint16_t>(-344), 1009, static_cast<uint16_t>(-320), 1010, 28, 1013, static_cast<uint16_t>(-384), 1016, static_cast<uint16_t>(-4), 1019, static_cast<uint16_t>(-4), 33840, static_cast<uint16_t>(-128), 1103, static_cast<uint16_t>(-128), 33872, static_cast<uint16_t>(-320), 1119, static_cast<uint16_t>(-320), 1121, static_cast<uint16_t>(-4), 1123, static_cast<uint16_t>(-4), 1125, static_cast<uint16_t>(-4), 1127, static_cast<uint16_t>(-4), 1129, static_cast<uint16_t>(-4), 1131, static_cast<uint16_t>(-4), 1133, static_cast<uint16_t>(-4), 1135, static_cast<uint16_t>(-4), 1137, static_cast<uint16_t>(-4), 1139, static_cast<uint16_t>(-4), 1141, static_cast<uint16_t>(-4), 1143, static_cast<uint16_t>(-4), 1145, static_cast<uint16_t>(-4), 1147, static_cast<uint16_t>(-4), 1149, static_cast<uint16_t>(-4), 1151, static_cast<uint16_t>(-4), 1153, static_cast<uint16_t>(-4), 1163, static_cast<uint16_t>(-4), 1165, static_cast<uint16_t>(-4), 1167, static_cast<uint16_t>(-4), 1169, static_cast<uint16_t>(-4), 1171, static_cast<uint16_t>(-4), 1173, static_cast<uint16_t>(-4), 1175, static_cast<uint16_t>(-4), 1177, static_cast<uint16_t>(-4), 1179, static_cast<uint16_t>(-4), 1181, static_cast<uint16_t>(-4), 1183, static_cast<uint16_t>(-4), 1185, static_cast<uint16_t>(-4), 1187, static_cast<uint16_t>(-4), 1189, static_cast<uint16_t>(-4), 1191, static_cast<uint16_t>(-4), 1193, static_cast<uint16_t>(-4), 1195, static_cast<uint16_t>(-4), 1197, static_cast<uint16_t>(-4), 1199, static_cast<uint16_t>(-4), 1201, static_cast<uint16_t>(-4), 1203, static_cast<uint16_t>(-4), 1205, static_cast<uint16_t>(-4), 1207, static_cast<uint16_t>(-4), 1209, static_cast<uint16_t>(-4), 1211, static_cast<uint16_t>(-4), 1213, static_cast<uint16_t>(-4), 1215, static_cast<uint16_t>(-4), 1218, static_cast<uint16_t>(-4), 1220, static_cast<uint16_t>(-4), 1222, static_cast<uint16_t>(-4), 1224, static_cast<uint16_t>(-4), 1226, static_cast<uint16_t>(-4), 1228, static_cast<uint16_t>(-4), 1230, static_cast<uint16_t>(-4), 1231, static_cast<uint16_t>(-60), 1233, static_cast<uint16_t>(-4), 1235, static_cast<uint16_t>(-4), 1237, static_cast<uint16_t>(-4), 1239, static_cast<uint16_t>(-4), 1241, static_cast<uint16_t>(-4), 1243, static_cast<uint16_t>(-4), 1245, static_cast<uint16_t>(-4), 1247, static_cast<uint16_t>(-4), 1249, static_cast<uint16_t>(-4), 1251, static_cast<uint16_t>(-4), 1253, static_cast<uint16_t>(-4), 1255, static_cast<uint16_t>(-4), 1257, static_cast<uint16_t>(-4), 1259, static_cast<uint16_t>(-4), 1261, static_cast<uint16_t>(-4), 1263, static_cast<uint16_t>(-4), 1265, static_cast<uint16_t>(-4), 1267, static_cast<uint16_t>(-4), 1269, static_cast<uint16_t>(-4), 1271, static_cast<uint16_t>(-4), 1273, static_cast<uint16_t>(-4), 1275, static_cast<uint16_t>(-4), 1277, static_cast<uint16_t>(-4), 1279, static_cast<uint16_t>(-4), 1281, static_cast<uint16_t>(-4), 1283, static_cast<uint16_t>(-4), 1285, static_cast<uint16_t>(-4), 1287, static_cast<uint16_t>(-4), 1289, static_cast<uint16_t>(-4), 1291, static_cast<uint16_t>(-4), 1293, static_cast<uint16_t>(-4), 1295, static_cast<uint16_t>(-4), 1297, static_cast<uint16_t>(-4), 1299, static_cast<uint16_t>(-4), 34145, static_cast<uint16_t>(-192), 1414, static_cast<uint16_t>(-192), 1415, 21, 7549, 15256, 7681, static_cast<uint16_t>(-4), 7683, static_cast<uint16_t>(-4), 7685, static_cast<uint16_t>(-4), 7687, static_cast<uint16_t>(-4), 7689, static_cast<uint16_t>(-4), 7691, static_cast<uint16_t>(-4), 7693, static_cast<uint16_t>(-4), 7695, static_cast<uint16_t>(-4), 7697, static_cast<uint16_t>(-4), 7699, static_cast<uint16_t>(-4), 7701, static_cast<uint16_t>(-4), 7703, static_cast<uint16_t>(-4), 7705, static_cast<uint16_t>(-4), 7707, static_cast<uint16_t>(-4), 7709, static_cast<uint16_t>(-4), 7711, static_cast<uint16_t>(-4), 7713, static_cast<uint16_t>(-4), 7715, static_cast<uint16_t>(-4), 7717, static_cast<uint16_t>(-4), 7719, static_cast<uint16_t>(-4), 7721, static_cast<uint16_t>(-4), 7723, static_cast<uint16_t>(-4), 7725, static_cast<uint16_t>(-4), 7727, static_cast<uint16_t>(-4), 7729, static_cast<uint16_t>(-4), 7731, static_cast<uint16_t>(-4), 7733, static_cast<uint16_t>(-4), 7735, static_cast<uint16_t>(-4), 7737, static_cast<uint16_t>(-4), 7739, static_cast<uint16_t>(-4), 7741, static_cast<uint16_t>(-4), 7743, static_cast<uint16_t>(-4), 7745, static_cast<uint16_t>(-4), 7747, static_cast<uint16_t>(-4), 7749, static_cast<uint16_t>(-4), 7751, static_cast<uint16_t>(-4), 7753, static_cast<uint16_t>(-4), 7755, static_cast<uint16_t>(-4), 7757, static_cast<uint16_t>(-4), 7759, static_cast<uint16_t>(-4), 7761, static_cast<uint16_t>(-4), 7763, static_cast<uint16_t>(-4), 7765, static_cast<uint16_t>(-4), 7767, static_cast<uint16_t>(-4), 7769, static_cast<uint16_t>(-4), 7771, static_cast<uint16_t>(-4), 7773, static_cast<uint16_t>(-4), 7775, static_cast<uint16_t>(-4), 7777, static_cast<uint16_t>(-4), 7779, static_cast<uint16_t>(-4), 7781, static_cast<uint16_t>(-4), 7783, static_cast<uint16_t>(-4), 7785, static_cast<uint16_t>(-4), 7787, static_cast<uint16_t>(-4), 7789, static_cast<uint16_t>(-4), 7791, static_cast<uint16_t>(-4), 7793, static_cast<uint16_t>(-4), 7795, static_cast<uint16_t>(-4), 7797, static_cast<uint16_t>(-4), 7799, static_cast<uint16_t>(-4), 7801, static_cast<uint16_t>(-4), 7803, static_cast<uint16_t>(-4), 7805, static_cast<uint16_t>(-4), 7807, static_cast<uint16_t>(-4), 7809, static_cast<uint16_t>(-4), 7811, static_cast<uint16_t>(-4), 7813, static_cast<uint16_t>(-4), 7815, static_cast<uint16_t>(-4), 7817, static_cast<uint16_t>(-4), 7819, static_cast<uint16_t>(-4), 7821, static_cast<uint16_t>(-4), 7823, static_cast<uint16_t>(-4), 7825, static_cast<uint16_t>(-4), 7827, static_cast<uint16_t>(-4), 7829, static_cast<uint16_t>(-4), 7830, 25, 7831, 29, 7832, 33, 7833, 37, 7834, 41, 7835, static_cast<uint16_t>(-236), 7841, static_cast<uint16_t>(-4), 7843, static_cast<uint16_t>(-4), 7845, static_cast<uint16_t>(-4), 7847, static_cast<uint16_t>(-4), 7849, static_cast<uint16_t>(-4), 7851, static_cast<uint16_t>(-4), 7853, static_cast<uint16_t>(-4), 7855, static_cast<uint16_t>(-4), 7857, static_cast<uint16_t>(-4), 7859, static_cast<uint16_t>(-4), 7861, static_cast<uint16_t>(-4), 7863, static_cast<uint16_t>(-4), 7865, static_cast<uint16_t>(-4), 7867, static_cast<uint16_t>(-4), 7869, static_cast<uint16_t>(-4), 7871, static_cast<uint16_t>(-4), 7873, static_cast<uint16_t>(-4), 7875, static_cast<uint16_t>(-4), 7877, static_cast<uint16_t>(-4), 7879, static_cast<uint16_t>(-4), 7881, static_cast<uint16_t>(-4), 7883, static_cast<uint16_t>(-4), 7885, static_cast<uint16_t>(-4), 7887, static_cast<uint16_t>(-4), 7889, static_cast<uint16_t>(-4), 7891, static_cast<uint16_t>(-4), 7893, static_cast<uint16_t>(-4), 7895, static_cast<uint16_t>(-4), 7897, static_cast<uint16_t>(-4), 7899, static_cast<uint16_t>(-4), 7901, static_cast<uint16_t>(-4), 7903, static_cast<uint16_t>(-4), 7905, static_cast<uint16_t>(-4), 7907, static_cast<uint16_t>(-4), 7909, static_cast<uint16_t>(-4), 7911, static_cast<uint16_t>(-4), 7913, static_cast<uint16_t>(-4), 7915, static_cast<uint16_t>(-4), 7917, static_cast<uint16_t>(-4), 7919, static_cast<uint16_t>(-4), 7921, static_cast<uint16_t>(-4), 7923, static_cast<uint16_t>(-4), 7925, static_cast<uint16_t>(-4), 7927, static_cast<uint16_t>(-4), 7929, static_cast<uint16_t>(-4), 40704, 32, 7943, 32, 40720, 32, 7957, 32, 40736, 32, 7975, 32, 40752, 32, 7991, 32, 40768, 32, 8005, 32, 8016, 45, 8017, 32, 8018, 49, 8019, 32, 8020, 53, 8021, 32, 8022, 57, 8023, 32, 40800, 32, 8039, 32, 40816, 296, 8049, 296, 40818, 344, 8053, 344, 40822, 400, 8055, 400, 40824, 512, 8057, 512, 40826, 448, 8059, 448, 40828, 504, 8061, 504, 8064, 61, 8065, 65, 8066, 69, 8067, 73, 8068, 77, 8069, 81, 8070, 85, 8071, 89, 8072, 93, 8073, 97, 8074, 101, 8075, 105, 8076, 109, 8077, 113, 8078, 117, 8079, 121, 8080, 125, 8081, 129, 8082, 133, 8083, 137, 8084, 141, 8085, 145, 8086, 149, 8087, 153, 8088, 157, 8089, 161, 8090, 165, 8091, 169, 8092, 173, 8093, 177, 8094, 181, 8095, 185, 8096, 189, 8097, 193, 8098, 197, 8099, 201, 8100, 205, 8101, 209, 8102, 213, 8103, 217, 8104, 221, 8105, 225, 8106, 229, 8107, 233, 8108, 237, 8109, 241, 8110, 245, 8111, 249, 40880, 32, 8113, 32, 8114, 253, 8115, 257, 8116, 261, 8118, 265, 8119, 269, 8124, 273, 8126, static_cast<uint16_t>(-28820), 8130, 277, 8131, 281, 8132, 285, 8134, 289, 8135, 293, 8140, 297, 40912, 32, 8145, 32, 8146, 301, 8147, 305, 8150, 309, 8151, 313, 40928, 32, 8161, 32, 8162, 317, 8163, 321, 8164, 325, 8165, 28, 8166, 329, 8167, 333, 8178, 337, 8179, 341, 8180, 345, 8182, 349, 8183, 353, 8188, 357, 8526, static_cast<uint16_t>(-112), 41328, static_cast<uint16_t>(-64), 8575, static_cast<uint16_t>(-64), 8580, static_cast<uint16_t>(-4), 42192, static_cast<uint16_t>(-104), 9449, static_cast<uint16_t>(-104), 44080, static_cast<uint16_t>(-192), 11358, static_cast<uint16_t>(-192), 11361, static_cast<uint16_t>(-4), 11365, static_cast<uint16_t>(-43180), 11366, static_cast<uint16_t>(-43168), 11368, static_cast<uint16_t>(-4), 11370, static_cast<uint16_t>(-4), 11372, static_cast<uint16_t>(-4), 11382, static_cast<uint16_t>(-4), 11393, static_cast<uint16_t>(-4), 11395, static_cast<uint16_t>(-4), 11397, static_cast<uint16_t>(-4), 11399, static_cast<uint16_t>(-4), 11401, static_cast<uint16_t>(-4), 11403, static_cast<uint16_t>(-4), 11405, static_cast<uint16_t>(-4), 11407, static_cast<uint16_t>(-4), 11409, static_cast<uint16_t>(-4), 11411, static_cast<uint16_t>(-4), 11413, static_cast<uint16_t>(-4), 11415, static_cast<uint16_t>(-4), 11417, static_cast<uint16_t>(-4), 11419, static_cast<uint16_t>(-4), 11421, static_cast<uint16_t>(-4), 11423, static_cast<uint16_t>(-4), 11425, static_cast<uint16_t>(-4), 11427, static_cast<uint16_t>(-4), 11429, static_cast<uint16_t>(-4), 11431, static_cast<uint16_t>(-4), 11433, static_cast<uint16_t>(-4), 11435, static_cast<uint16_t>(-4), 11437, static_cast<uint16_t>(-4), 11439, static_cast<uint16_t>(-4), 11441, static_cast<uint16_t>(-4), 11443, static_cast<uint16_t>(-4), 11445, static_cast<uint16_t>(-4), 11447, static_cast<uint16_t>(-4), 11449, static_cast<uint16_t>(-4), 11451, static_cast<uint16_t>(-4), 11453, static_cast<uint16_t>(-4), 11455, static_cast<uint16_t>(-4), 11457, static_cast<uint16_t>(-4), 11459, static_cast<uint16_t>(-4), 11461, static_cast<uint16_t>(-4), 11463, static_cast<uint16_t>(-4), 11465, static_cast<uint16_t>(-4), 11467, static_cast<uint16_t>(-4), 11469, static_cast<uint16_t>(-4), 11471, static_cast<uint16_t>(-4), 11473, static_cast<uint16_t>(-4), 11475, static_cast<uint16_t>(-4), 11477, static_cast<uint16_t>(-4), 11479, static_cast<uint16_t>(-4), 11481, static_cast<uint16_t>(-4), 11483, static_cast<uint16_t>(-4), 11485, static_cast<uint16_t>(-4), 11487, static_cast<uint16_t>(-4), 11489, static_cast<uint16_t>(-4), 11491, static_cast<uint16_t>(-4), 44288, static_cast<uint16_t>(-29056), 11557, static_cast<uint16_t>(-29056) }; // NOLINT
-static const MultiCharacterSpecialCase kToUppercaseMultiStrings1[] = { {2, {70, 70}}, {2, {70, 73}}, {2, {70, 76}}, {3, {70, 70, 73}}, {3, {70, 70, 76}}, {2, {83, 84}}, {2, {83, 84}}, {2, {1348, 1350}}, {2, {1348, 1333}}, {2, {1348, 1339}}, {2, {1358, 1350}}, {2, {1348, 1341}}, {0, {0}} }; // NOLINT
+static const int32_t kToUppercaseTable0[1242] = { 1073741921, -128, 122, -128, 181, 2972, 223, 1, 1073742048, -128, 246, -128, 1073742072, -128, 254, -128, 255, 484, 257, -4, 259, -4, 261, -4, 263, -4, 265, -4, 267, -4, 269, -4, 271, -4, 273, -4, 275, -4, 277, -4, 279, -4, 281, -4, 283, -4, 285, -4, 287, -4, 289, -4, 291, -4, 293, -4, 295, -4, 297, -4, 299, -4, 301, -4, 303, -4, 305, -928, 307, -4, 309, -4, 311, -4, 314, -4, 316, -4, 318, -4, 320, -4, 322, -4, 324, -4, 326, -4, 328, -4, 329, 5, 331, -4, 333, -4, 335, -4, 337, -4, 339, -4, 341, -4, 343, -4, 345, -4, 347, -4, 349, -4, 351, -4, 353, -4, 355, -4, 357, -4, 359, -4, 361, -4, 363, -4, 365, -4, 367, -4, 369, -4, 371, -4, 373, -4, 375, -4, 378, -4, 380, -4, 382, -4, 383, -1200, 384, 780, 387, -4, 389, -4, 392, -4, 396, -4, 402, -4, 405, 388, 409, -4, 410, 652, 414, 520, 417, -4, 419, -4, 421, -4, 424, -4, 429, -4, 432, -4, 436, -4, 438, -4, 441, -4, 445, -4, 447, 224, 453, -4, 454, -8, 456, -4, 457, -8, 459, -4, 460, -8, 462, -4, 464, -4, 466, -4, 468, -4, 470, -4, 472, -4, 474, -4, 476, -4, 477, -316, 479, -4, 481, -4, 483, -4, 485, -4, 487, -4, 489, -4, 491, -4, 493, -4, 495, -4, 496, 9, 498, -4, 499, -8, 501, -4, 505, -4, 507, -4, 509, -4, 511, -4, 513, -4, 515, -4, 517, -4, 519, -4, 521, -4, 523, -4, 525, -4, 527, -4, 529, -4, 531, -4, 533, -4, 535, -4, 537, -4, 539, -4, 541, -4, 543, -4, 547, -4, 549, -4, 551, -4, 553, -4, 555, -4, 557, -4, 559, -4, 561, -4, 563, -4, 572, -4, 578, -4, 583, -4, 585, -4, 587, -4, 589, -4, 591, -4, 595, -840, 596, -824, 1073742422, -820, 599, -820, 601, -808, 603, -812, 608, -820, 611, -828, 616, -836, 617, -844, 619, 42972, 623, -844, 626, -852, 629, -856, 637, 42908, 640, -872, 643, -872, 648, -872, 649, -276, 1073742474, -868, 651, -868, 652, -284, 658, -876, 837, 336, 1073742715, 520, 893, 520, 912, 13, 940, -152, 1073742765, -148, 943, -148, 944, 17, 1073742769, -128, 961, -128, 962, -124, 1073742787, -128, 971, -128, 972, -256, 1073742797, -252, 974, -252, 976, -248, 977, -228, 981, -188, 982, -216, 985, -4, 987, -4, 989, -4, 991, -4, 993, -4, 995, -4, 997, -4, 999, -4, 1001, -4, 1003, -4, 1005, -4, 1007, -4, 1008, -344, 1009, -320, 1010, 28, 1013, -384, 1016, -4, 1019, -4, 1073742896, -128, 1103, -128, 1073742928, -320, 1119, -320, 1121, -4, 1123, -4, 1125, -4, 1127, -4, 1129, -4, 1131, -4, 1133, -4, 1135, -4, 1137, -4, 1139, -4, 1141, -4, 1143, -4, 1145, -4, 1147, -4, 1149, -4, 1151, -4, 1153, -4, 1163, -4, 1165, -4, 1167, -4, 1169, -4, 1171, -4, 1173, -4, 1175, -4, 1177, -4, 1179, -4, 1181, -4, 1183, -4, 1185, -4, 1187, -4, 1189, -4, 1191, -4, 1193, -4, 1195, -4, 1197, -4, 1199, -4, 1201, -4, 1203, -4, 1205, -4, 1207, -4, 1209, -4, 1211, -4, 1213, -4, 1215, -4, 1218, -4, 1220, -4, 1222, -4, 1224, -4, 1226, -4, 1228, -4, 1230, -4, 1231, -60, 1233, -4, 1235, -4, 1237, -4, 1239, -4, 1241, -4, 1243, -4, 1245, -4, 1247, -4, 1249, -4, 1251, -4, 1253, -4, 1255, -4, 1257, -4, 1259, -4, 1261, -4, 1263, -4, 1265, -4, 1267, -4, 1269, -4, 1271, -4, 1273, -4, 1275, -4, 1277, -4, 1279, -4, 1281, -4, 1283, -4, 1285, -4, 1287, -4, 1289, -4, 1291, -4, 1293, -4, 1295, -4, 1297, -4, 1299, -4, 1073743201, -192, 1414, -192, 1415, 21, 7549, 15256, 7681, -4, 7683, -4, 7685, -4, 7687, -4, 7689, -4, 7691, -4, 7693, -4, 7695, -4, 7697, -4, 7699, -4, 7701, -4, 7703, -4, 7705, -4, 7707, -4, 7709, -4, 7711, -4, 7713, -4, 7715, -4, 7717, -4, 7719, -4, 7721, -4, 7723, -4, 7725, -4, 7727, -4, 7729, -4, 7731, -4, 7733, -4, 7735, -4, 7737, -4, 7739, -4, 7741, -4, 7743, -4, 7745, -4, 7747, -4, 7749, -4, 7751, -4, 7753, -4, 7755, -4, 7757, -4, 7759, -4, 7761, -4, 7763, -4, 7765, -4, 7767, -4, 7769, -4, 7771, -4, 7773, -4, 7775, -4, 7777, -4, 7779, -4, 7781, -4, 7783, -4, 7785, -4, 7787, -4, 7789, -4, 7791, -4, 7793, -4, 7795, -4, 7797, -4, 7799, -4, 7801, -4, 7803, -4, 7805, -4, 7807, -4, 7809, -4, 7811, -4, 7813, -4, 7815, -4, 7817, -4, 7819, -4, 7821, -4, 7823, -4, 7825, -4, 7827, -4, 7829, -4, 7830, 25, 7831, 29, 7832, 33, 7833, 37, 7834, 41, 7835, -236, 7841, -4, 7843, -4, 7845, -4, 7847, -4, 7849, -4, 7851, -4, 7853, -4, 7855, -4, 7857, -4, 7859, -4, 7861, -4, 7863, -4, 7865, -4, 7867, -4, 7869, -4, 7871, -4, 7873, -4, 7875, -4, 7877, -4, 7879, -4, 7881, -4, 7883, -4, 7885, -4, 7887, -4, 7889, -4, 7891, -4, 7893, -4, 7895, -4, 7897, -4, 7899, -4, 7901, -4, 7903, -4, 7905, -4, 7907, -4, 7909, -4, 7911, -4, 7913, -4, 7915, -4, 7917, -4, 7919, -4, 7921, -4, 7923, -4, 7925, -4, 7927, -4, 7929, -4, 1073749760, 32, 7943, 32, 1073749776, 32, 7957, 32, 1073749792, 32, 7975, 32, 1073749808, 32, 7991, 32, 1073749824, 32, 8005, 32, 8016, 45, 8017, 32, 8018, 49, 8019, 32, 8020, 53, 8021, 32, 8022, 57, 8023, 32, 1073749856, 32, 8039, 32, 1073749872, 296, 8049, 296, 1073749874, 344, 8053, 344, 1073749878, 400, 8055, 400, 1073749880, 512, 8057, 512, 1073749882, 448, 8059, 448, 1073749884, 504, 8061, 504, 8064, 61, 8065, 65, 8066, 69, 8067, 73, 8068, 77, 8069, 81, 8070, 85, 8071, 89, 8072, 93, 8073, 97, 8074, 101, 8075, 105, 8076, 109, 8077, 113, 8078, 117, 8079, 121, 8080, 125, 8081, 129, 8082, 133, 8083, 137, 8084, 141, 8085, 145, 8086, 149, 8087, 153, 8088, 157, 8089, 161, 8090, 165, 8091, 169, 8092, 173, 8093, 177, 8094, 181, 8095, 185, 8096, 189, 8097, 193, 8098, 197, 8099, 201, 8100, 205, 8101, 209, 8102, 213, 8103, 217, 8104, 221, 8105, 225, 8106, 229, 8107, 233, 8108, 237, 8109, 241, 8110, 245, 8111, 249, 1073749936, 32, 8113, 32, 8114, 253, 8115, 257, 8116, 261, 8118, 265, 8119, 269, 8124, 273, 8126, -28820, 8130, 277, 8131, 281, 8132, 285, 8134, 289, 8135, 293, 8140, 297, 1073749968, 32, 8145, 32, 8146, 301, 8147, 305, 8150, 309, 8151, 313, 1073749984, 32, 8161, 32, 8162, 317, 8163, 321, 8164, 325, 8165, 28, 8166, 329, 8167, 333, 8178, 337, 8179, 341, 8180, 345, 8182, 349, 8183, 353, 8188, 357, 8526, -112, 1073750384, -64, 8575, -64, 8580, -4, 1073751248, -104, 9449, -104, 1073753136, -192, 11358, -192, 11361, -4, 11365, -43180, 11366, -43168, 11368, -4, 11370, -4, 11372, -4, 11382, -4, 11393, -4, 11395, -4, 11397, -4, 11399, -4, 11401, -4, 11403, -4, 11405, -4, 11407, -4, 11409, -4, 11411, -4, 11413, -4, 11415, -4, 11417, -4, 11419, -4, 11421, -4, 11423, -4, 11425, -4, 11427, -4, 11429, -4, 11431, -4, 11433, -4, 11435, -4, 11437, -4, 11439, -4, 11441, -4, 11443, -4, 11445, -4, 11447, -4, 11449, -4, 11451, -4, 11453, -4, 11455, -4, 11457, -4, 11459, -4, 11461, -4, 11463, -4, 11465, -4, 11467, -4, 11469, -4, 11471, -4, 11473, -4, 11475, -4, 11477, -4, 11479, -4, 11481, -4, 11483, -4, 11485, -4, 11487, -4, 11489, -4, 11491, -4, 1073753344, -29056, 11557, -29056 }; // NOLINT
+static const MultiCharacterSpecialCase<3> kToUppercaseMultiStrings1[] = { {2, {70, 70}}, {2, {70, 73}}, {2, {70, 76}}, {3, {70, 70, 73}}, {3, {70, 70, 76}}, {2, {83, 84}}, {2, {83, 84}}, {2, {1348, 1350}}, {2, {1348, 1333}}, {2, {1348, 1339}}, {2, {1358, 1350}}, {2, {1348, 1341}}, {0, {0}} }; // NOLINT
 static const uint16_t kToUppercaseTable1Size = 14;
-static const uint16_t kToUppercaseTable1[28] = { 31488, 1, 31489, 5, 31490, 9, 31491, 13, 31492, 17, 31493, 21, 31494, 25, 31507, 29, 31508, 33, 31509, 37, 31510, 41, 31511, 45, 65345, static_cast<uint16_t>(-128), 32602, static_cast<uint16_t>(-128) }; // NOLINT
-static const MultiCharacterSpecialCase kToUppercaseMultiStrings2[] = { {0, {0}} }; // NOLINT
+static const int32_t kToUppercaseTable1[28] = { 31488, 1, 31489, 5, 31490, 9, 31491, 13, 31492, 17, 31493, 21, 31494, 25, 31507, 29, 31508, 33, 31509, 37, 31510, 41, 31511, 45, 1073774401, -128, 32602, -128 }; // NOLINT
+static const MultiCharacterSpecialCase<3> kToUppercaseMultiStrings2[] = { {0, {0}} }; // NOLINT
 static const uint16_t kToUppercaseTable2Size = 2;
-static const uint16_t kToUppercaseTable2[4] = { 33832, static_cast<uint16_t>(-160), 1103, static_cast<uint16_t>(-160) }; // NOLINT
+static const int32_t kToUppercaseTable2[4] = { 1073742888, -160, 1103, -160 }; // NOLINT
 int ToUppercase::Convert(uchar c,
                       uchar n,
                       uchar* result,
@@ -806,11 +634,121 @@ int ToUppercase::Convert(uchar c,
   }
 }
 
+static const MultiCharacterSpecialCase<1> kEcma262CanonicalizeMultiStrings0[] = { {0, {0}} }; // NOLINT
+static const uint16_t kEcma262CanonicalizeTable0Size = 529;
+static const int32_t kEcma262CanonicalizeTable0[1058] = { 1073741921, -128, 122, -128, 181, 2972, 1073742048, -128, 246, -128, 1073742072, -128, 254, -128, 255, 484, 257, -4, 259, -4, 261, -4, 263, -4, 265, -4, 267, -4, 269, -4, 271, -4, 273, -4, 275, -4, 277, -4, 279, -4, 281, -4, 283, -4, 285, -4, 287, -4, 289, -4, 291, -4, 293, -4, 295, -4, 297, -4, 299, -4, 301, -4, 303, -4, 307, -4, 309, -4, 311, -4, 314, -4, 316, -4, 318, -4, 320, -4, 322, -4, 324, -4, 326, -4, 328, -4, 331, -4, 333, -4, 335, -4, 337, -4, 339, -4, 341, -4, 343, -4, 345, -4, 347, -4, 349, -4, 351, -4, 353, -4, 355, -4, 357, -4, 359, -4, 361, -4, 363, -4, 365, -4, 367, -4, 369, -4, 371, -4, 373, -4, 375, -4, 378, -4, 380, -4, 382, -4, 384, 780, 387, -4, 389, -4, 392, -4, 396, -4, 402, -4, 405, 388, 409, -4, 410, 652, 414, 520, 417, -4, 419, -4, 421, -4, 424, -4, 429, -4, 432, -4, 436, -4, 438, -4, 441, -4, 445, -4, 447, 224, 453, -4, 454, -8, 456, -4, 457, -8, 459, -4, 460, -8, 462, -4, 464, -4, 466, -4, 468, -4, 470, -4, 472, -4, 474, -4, 476, -4, 477, -316, 479, -4, 481, -4, 483, -4, 485, -4, 487, -4, 489, -4, 491, -4, 493, -4, 495, -4, 498, -4, 499, -8, 501, -4, 505, -4, 507, -4, 509, -4, 511, -4, 513, -4, 515, -4, 517, -4, 519, -4, 521, -4, 523, -4, 525, -4, 527, -4, 529, -4, 531, -4, 533, -4, 535, -4, 537, -4, 539, -4, 541, -4, 543, -4, 547, -4, 549, -4, 551, -4, 553, -4, 555, -4, 557, -4, 559, -4, 561, -4, 563, -4, 572, -4, 578, -4, 583, -4, 585, -4, 587, -4, 589, -4, 591, -4, 595, -840, 596, -824, 1073742422, -820, 599, -820, 601, -808, 603, -812, 608, -820, 611, -828, 616, -836, 617, -844, 619, 42972, 623, -844, 626, -852, 629, -856, 637, 42908, 640, -872, 643, -872, 648, -872, 649, -276, 1073742474, -868, 651, -868, 652, -284, 658, -876, 837, 336, 1073742715, 520, 893, 520, 940, -152, 1073742765, -148, 943, -148, 1073742769, -128, 961, -128, 962, -124, 1073742787, -128, 971, -128, 972, -256, 1073742797, -252, 974, -252, 976, -248, 977, -228, 981, -188, 982, -216, 985, -4, 987, -4, 989, -4, 991, -4, 993, -4, 995, -4, 997, -4, 999, -4, 1001, -4, 1003, -4, 1005, -4, 1007, -4, 1008, -344, 1009, -320, 1010, 28, 1013, -384, 1016, -4, 1019, -4, 1073742896, -128, 1103, -128, 1073742928, -320, 1119, -320, 1121, -4, 1123, -4, 1125, -4, 1127, -4, 1129, -4, 1131, -4, 1133, -4, 1135, -4, 1137, -4, 1139, -4, 1141, -4, 1143, -4, 1145, -4, 1147, -4, 1149, -4, 1151, -4, 1153, -4, 1163, -4, 1165, -4, 1167, -4, 1169, -4, 1171, -4, 1173, -4, 1175, -4, 1177, -4, 1179, -4, 1181, -4, 1183, -4, 1185, -4, 1187, -4, 1189, -4, 1191, -4, 1193, -4, 1195, -4, 1197, -4, 1199, -4, 1201, -4, 1203, -4, 1205, -4, 1207, -4, 1209, -4, 1211, -4, 1213, -4, 1215, -4, 1218, -4, 1220, -4, 1222, -4, 1224, -4, 1226, -4, 1228, -4, 1230, -4, 1231, -60, 1233, -4, 1235, -4, 1237, -4, 1239, -4, 1241, -4, 1243, -4, 1245, -4, 1247, -4, 1249, -4, 1251, -4, 1253, -4, 1255, -4, 1257, -4, 1259, -4, 1261, -4, 1263, -4, 1265, -4, 1267, -4, 1269, -4, 1271, -4, 1273, -4, 1275, -4, 1277, -4, 1279, -4, 1281, -4, 1283, -4, 1285, -4, 1287, -4, 1289, -4, 1291, -4, 1293, -4, 1295, -4, 1297, -4, 1299, -4, 1073743201, -192, 1414, -192, 7549, 15256, 7681, -4, 7683, -4, 7685, -4, 7687, -4, 7689, -4, 7691, -4, 7693, -4, 7695, -4, 7697, -4, 7699, -4, 7701, -4, 7703, -4, 7705, -4, 7707, -4, 7709, -4, 7711, -4, 7713, -4, 7715, -4, 7717, -4, 7719, -4, 7721, -4, 7723, -4, 7725, -4, 7727, -4, 7729, -4, 7731, -4, 7733, -4, 7735, -4, 7737, -4, 7739, -4, 7741, -4, 7743, -4, 7745, -4, 7747, -4, 7749, -4, 7751, -4, 7753, -4, 7755, -4, 7757, -4, 7759, -4, 7761, -4, 7763, -4, 7765, -4, 7767, -4, 7769, -4, 7771, -4, 7773, -4, 7775, -4, 7777, -4, 7779, -4, 7781, -4, 7783, -4, 7785, -4, 7787, -4, 7789, -4, 7791, -4, 7793, -4, 7795, -4, 7797, -4, 7799, -4, 7801, -4, 7803, -4, 7805, -4, 7807, -4, 7809, -4, 7811, -4, 7813, -4, 7815, -4, 7817, -4, 7819, -4, 7821, -4, 7823, -4, 7825, -4, 7827, -4, 7829, -4, 7835, -236, 7841, -4, 7843, -4, 7845, -4, 7847, -4, 7849, -4, 7851, -4, 7853, -4, 7855, -4, 7857, -4, 7859, -4, 7861, -4, 7863, -4, 7865, -4, 7867, -4, 7869, -4, 7871, -4, 7873, -4, 7875, -4, 7877, -4, 7879, -4, 7881, -4, 7883, -4, 7885, -4, 7887, -4, 7889, -4, 7891, -4, 7893, -4, 7895, -4, 7897, -4, 7899, -4, 7901, -4, 7903, -4, 7905, -4, 7907, -4, 7909, -4, 7911, -4, 7913, -4, 7915, -4, 7917, -4, 7919, -4, 7921, -4, 7923, -4, 7925, -4, 7927, -4, 7929, -4, 1073749760, 32, 7943, 32, 1073749776, 32, 7957, 32, 1073749792, 32, 7975, 32, 1073749808, 32, 7991, 32, 1073749824, 32, 8005, 32, 8017, 32, 8019, 32, 8021, 32, 8023, 32, 1073749856, 32, 8039, 32, 1073749872, 296, 8049, 296, 1073749874, 344, 8053, 344, 1073749878, 400, 8055, 400, 1073749880, 512, 8057, 512, 1073749882, 448, 8059, 448, 1073749884, 504, 8061, 504, 1073749936, 32, 8113, 32, 8126, -28820, 1073749968, 32, 8145, 32, 1073749984, 32, 8161, 32, 8165, 28, 8526, -112, 1073750384, -64, 8575, -64, 8580, -4, 1073751248, -104, 9449, -104, 1073753136, -192, 11358, -192, 11361, -4, 11365, -43180, 11366, -43168, 11368, -4, 11370, -4, 11372, -4, 11382, -4, 11393, -4, 11395, -4, 11397, -4, 11399, -4, 11401, -4, 11403, -4, 11405, -4, 11407, -4, 11409, -4, 11411, -4, 11413, -4, 11415, -4, 11417, -4, 11419, -4, 11421, -4, 11423, -4, 11425, -4, 11427, -4, 11429, -4, 11431, -4, 11433, -4, 11435, -4, 11437, -4, 11439, -4, 11441, -4, 11443, -4, 11445, -4, 11447, -4, 11449, -4, 11451, -4, 11453, -4, 11455, -4, 11457, -4, 11459, -4, 11461, -4, 11463, -4, 11465, -4, 11467, -4, 11469, -4, 11471, -4, 11473, -4, 11475, -4, 11477, -4, 11479, -4, 11481, -4, 11483, -4, 11485, -4, 11487, -4, 11489, -4, 11491, -4, 1073753344, -29056, 11557, -29056 }; // NOLINT
+static const MultiCharacterSpecialCase<1> kEcma262CanonicalizeMultiStrings1[] = { {0, {0}} }; // NOLINT
+static const uint16_t kEcma262CanonicalizeTable1Size = 2;
+static const int32_t kEcma262CanonicalizeTable1[4] = { 1073774401, -128, 32602, -128 }; // NOLINT
+static const MultiCharacterSpecialCase<1> kEcma262CanonicalizeMultiStrings2[] = { {0, {0}} }; // NOLINT
+static const uint16_t kEcma262CanonicalizeTable2Size = 2;
+static const int32_t kEcma262CanonicalizeTable2[4] = { 1073742888, -160, 1103, -160 }; // NOLINT
+int Ecma262Canonicalize::Convert(uchar c,
+                      uchar n,
+                      uchar* result,
+                      bool* allow_caching_ptr) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupMapping(kEcma262CanonicalizeTable0,
+                                     kEcma262CanonicalizeTable0Size,
+                                     kEcma262CanonicalizeMultiStrings0,
+                                     c,
+                                     n,
+                                     result,
+                                     allow_caching_ptr);
+    case 1: return LookupMapping(kEcma262CanonicalizeTable1,
+                                     kEcma262CanonicalizeTable1Size,
+                                     kEcma262CanonicalizeMultiStrings1,
+                                     c,
+                                     n,
+                                     result,
+                                     allow_caching_ptr);
+    case 2: return LookupMapping(kEcma262CanonicalizeTable2,
+                                     kEcma262CanonicalizeTable2Size,
+                                     kEcma262CanonicalizeMultiStrings2,
+                                     c,
+                                     n,
+                                     result,
+                                     allow_caching_ptr);
+    default: return 0;
+  }
+}
+
+static const MultiCharacterSpecialCase<4> kEcma262UnCanonicalizeMultiStrings0[] = { {2, {65, 97}}, {2, {66, 98}}, {2, {67, 99}}, {2, {68, 100}}, {2, {69, 101}}, {2, {70, 102}}, {2, {71, 103}}, {2, {72, 104}}, {2, {73, 105}}, {2, {74, 106}}, {2, {75, 107}}, {2, {76, 108}}, {2, {77, 109}}, {2, {78, 110}}, {2, {79, 111}}, {2, {80, 112}}, {2, {81, 113}}, {2, {82, 114}}, {2, {83, 115}}, {2, {84, 116}}, {2, {85, 117}}, {2, {86, 118}}, {2, {87, 119}}, {2, {88, 120}}, {2, {89, 121}}, {2, {90, 122}}, {2, {65, 97}}, {2, {66, 98}}, {2, {67, 99}}, {2, {68, 100}}, {2, {69, 101}}, {2, {70, 102}}, {2, {71, 103}}, {2, {72, 104}}, {2, {73, 105}}, {2, {74, 106}}, {2, {75, 107}}, {2, {76, 108}}, {2, {77, 109}}, {2, {78, 110}}, {2, {79, 111}}, {2, {80, 112}}, {2, {81, 113}}, {2, {82, 114}}, {2, {83, 115}}, {2, {84, 116}}, {2, {85, 117}}, {2, {86, 118}}, {2, {87, 119}}, {2, {88, 120}}, {2, {89, 121}}, {2, {90, 122}}, {3, {181, 924, 956}}, {2, {192, 224}}, {2, {193, 225}}, {2, {194, 226}}, {2, {195, 227}}, {2, {196, 228}}, {2, {197, 229}}, {2, {198, 230}}, {2, {199, 231}}, {2, {200, 232}}, {2, {201, 233}}, {2, {202, 234}}, {2, {203, 235}}, {2, {204, 236}}, {2, {205, 237}}, {2, {206, 238}}, {2, {207, 239}}, {2, {208, 240}}, {2, {209, 241}}, {2, {210, 242}}, {2, {211, 243}}, {2, {212, 244}}, {2, {213, 245}}, {2, {214, 246}}, {2, {216, 248}}, {2, {217, 249}}, {2, {218, 250}}, {2, {219, 251}}, {2, {220, 252}}, {2, {221, 253}}, {2, {222, 254}}, {2, {192, 224}}, {2, {193, 225}}, {2, {194, 226}}, {2, {195, 227}}, {2, {196, 228}}, {2, {197, 229}}, {2, {198, 230}}, {2, {199, 231}}, {2, {200, 232}}, {2, {201, 233}}, {2, {202, 234}}, {2, {203, 235}}, {2, {204, 236}}, {2, {205, 237}}, {2, {206, 238}}, {2, {207, 239}}, {2, {208, 240}}, {2, {209, 241}}, {2, {210, 242}}, {2, {211, 243}}, {2, {212, 244}}, {2, {213, 245}}, {2, {214, 246}}, {2, {216, 248}}, {2, {217, 249}}, {2, {218, 250}}, {2, {219, 251}}, {2, {220, 252}}, {2, {221, 253}}, {2, {222, 254}}, {2, {255, 376}}, {2, {256, 257}}, {2, {256, 257}}, {2, {258, 259}}, {2, {258, 259}}, {2, {260, 261}}, {2, {260, 261}}, {2, {262, 263}}, {2, {262, 263}}, {2, {264, 265}}, {2, {264, 265}}, {2, {266, 267}}, {2, {266, 267}}, {2, {268, 269}}, {2, {268, 269}}, {2, {270, 271}}, {2, {270, 271}}, {2, {272, 273}}, {2, {272, 273}}, {2, {274, 275}}, {2, {274, 275}}, {2, {276, 277}}, {2, {276, 277}}, {2, {278, 279}}, {2, {278, 279}}, {2, {280, 281}}, {2, {280, 281}}, {2, {282, 283}}, {2, {282, 283}}, {2, {284, 285}}, {2, {284, 285}}, {2, {286, 287}}, {2, {286, 287}}, {2, {288, 289}}, {2, {288, 289}}, {2, {290, 291}}, {2, {290, 291}}, {2, {292, 293}}, {2, {292, 293}}, {2, {294, 295}}, {2, {294, 295}}, {2, {296, 297}}, {2, {296, 297}}, {2, {298, 299}}, {2, {298, 299}}, {2, {300, 301}}, {2, {300, 301}}, {2, {302, 303}}, {2, {302, 303}}, {2, {306, 307}}, {2, {306, 307}}, {2, {308, 309}}, {2, {308, 309}}, {2, {310, 311}}, {2, {310, 311}}, {2, {313, 314}}, {2, {313, 314}}, {2, {315, 316}}, {2, {315, 316}}, {2, {317, 318}}, {2, {317, 318}}, {2, {319, 320}}, {2, {319, 320}}, {2, {321, 322}}, {2, {321, 322}}, {2, {323, 324}}, {2, {323, 324}}, {2, {325, 326}}, {2, {325, 326}}, {2, {327, 328}}, {2, {327, 328}}, {2, {330, 331}}, {2, {330, 331}}, {2, {332, 333}}, {2, {332, 333}}, {2, {334, 335}}, {2, {334, 335}}, {2, {336, 337}}, {2, {336, 337}}, {2, {338, 339}}, {2, {338, 339}}, {2, {340, 341}}, {2, {340, 341}}, {2, {342, 343}}, {2, {342, 343}}, {2, {344, 345}}, {2, {344, 345}}, {2, {346, 347}}, {2, {346, 347}}, {2, {348, 349}}, {2, {348, 349}}, {2, {350, 351}}, {2, {350, 351}}, {2, {352, 353}}, {2, {352, 353}}, {2, {354, 355}}, {2, {354, 355}}, {2, {356, 357}}, {2, {356, 357}}, {2, {358, 359}}, {2, {358, 359}}, {2, {360, 361}}, {2, {360, 361}}, {2, {362, 363}}, {2, {362, 363}}, {2, {364, 365}}, {2, {364, 365}}, {2, {366, 367}}, {2, {366, 367}}, {2, {368, 369}}, {2, {368, 369}}, {2, {370, 371}}, {2, {370, 371}}, {2, {372, 373}}, {2, {372, 373}}, {2, {374, 375}}, {2, {374, 375}}, {2, {255, 376}}, {2, {377, 378}}, {2, {377, 378}}, {2, {379, 380}}, {2, {379, 380}}, {2, {381, 382}}, {2, {381, 382}}, {2, {384, 579}}, {2, {385, 595}}, {2, {386, 387}}, {2, {386, 387}}, {2, {388, 389}}, {2, {388, 389}}, {2, {390, 596}}, {2, {391, 392}}, {2, {391, 392}}, {2, {393, 598}}, {2, {394, 599}}, {2, {395, 396}}, {2, {395, 396}}, {2, {398, 477}}, {2, {399, 601}}, {2, {400, 603}}, {2, {401, 402}}, {2, {401, 402}}, {2, {403, 608}}, {2, {404, 611}}, {2, {405, 502}}, {2, {406, 617}}, {2, {407, 616}}, {2, {408, 409}}, {2, {408, 409}}, {2, {410, 573}}, {2, {412, 623}}, {2, {413, 626}}, {2, {414, 544}}, {2, {415, 629}}, {2, {416, 417}}, {2, {416, 417}}, {2, {418, 419}}, {2, {418, 419}}, {2, {420, 421}}, {2, {420, 421}}, {2, {422, 640}}, {2, {423, 424}}, {2, {423, 424}}, {2, {425, 643}}, {2, {428, 429}}, {2, {428, 429}}, {2, {430, 648}}, {2, {431, 432}}, {2, {431, 432}}, {2, {433, 650}}, {2, {434, 651}}, {2, {435, 436}}, {2, {435, 436}}, {2, {437, 438}}, {2, {437, 438}}, {2, {439, 658}}, {2, {440, 441}}, {2, {440, 441}}, {2, {444, 445}}, {2, {444, 445}}, {2, {447, 503}}, {3, {452, 453, 454}}, {3, {452, 453, 454}}, {3, {452, 453, 454}}, {3, {455, 456, 457}}, {3, {455, 456, 457}}, {3, {455, 456, 457}}, {3, {458, 459, 460}}, {3, {458, 459, 460}}, {3, {458, 459, 460}}, {2, {461, 462}}, {2, {461, 462}}, {2, {463, 464}}, {2, {463, 464}}, {2, {465, 466}}, {2, {465, 466}}, {2, {467, 468}}, {2, {467, 468}}, {2, {469, 470}}, {2, {469, 470}}, {2, {471, 472}}, {2, {471, 472}}, {2, {473, 474}}, {2, {473, 474}}, {2, {475, 476}}, {2, {475, 476}}, {2, {398, 477}}, {2, {478, 479}}, {2, {478, 479}}, {2, {480, 481}}, {2, {480, 481}}, {2, {482, 483}}, {2, {482, 483}}, {2, {484, 485}}, {2, {484, 485}}, {2, {486, 487}}, {2, {486, 487}}, {2, {488, 489}}, {2, {488, 489}}, {2, {490, 491}}, {2, {490, 491}}, {2, {492, 493}}, {2, {492, 493}}, {2, {494, 495}}, {2, {494, 495}}, {3, {497, 498, 499}}, {3, {497, 498, 499}}, {3, {497, 498, 499}}, {2, {500, 501}}, {2, {500, 501}}, {2, {405, 502}}, {2, {447, 503}}, {2, {504, 505}}, {2, {504, 505}}, {2, {506, 507}}, {2, {506, 507}}, {2, {508, 509}}, {2, {508, 509}}, {2, {510, 511}}, {2, {510, 511}}, {2, {512, 513}}, {2, {512, 513}}, {2, {514, 515}}, {2, {514, 515}}, {2, {516, 517}}, {2, {516, 517}}, {2, {518, 519}}, {2, {518, 519}}, {2, {520, 521}}, {2, {520, 521}}, {2, {522, 523}}, {2, {522, 523}}, {2, {524, 525}}, {2, {524, 525}}, {2, {526, 527}}, {2, {526, 527}}, {2, {528, 529}}, {2, {528, 529}}, {2, {530, 531}}, {2, {530, 531}}, {2, {532, 533}}, {2, {532, 533}}, {2, {534, 535}}, {2, {534, 535}}, {2, {536, 537}}, {2, {536, 537}}, {2, {538, 539}}, {2, {538, 539}}, {2, {540, 541}}, {2, {540, 541}}, {2, {542, 543}}, {2, {542, 543}}, {2, {414, 544}}, {2, {546, 547}}, {2, {546, 547}}, {2, {548, 549}}, {2, {548, 549}}, {2, {550, 551}}, {2, {550, 551}}, {2, {552, 553}}, {2, {552, 553}}, {2, {554, 555}}, {2, {554, 555}}, {2, {556, 557}}, {2, {556, 557}}, {2, {558, 559}}, {2, {558, 559}}, {2, {560, 561}}, {2, {560, 561}}, {2, {562, 563}}, {2, {562, 563}}, {2, {570, 11365}}, {2, {571, 572}}, {2, {571, 572}}, {2, {410, 573}}, {2, {574, 11366}}, {2, {577, 578}}, {2, {577, 578}}, {2, {384, 579}}, {2, {580, 649}}, {2, {581, 652}}, {2, {582, 583}}, {2, {582, 583}}, {2, {584, 585}}, {2, {584, 585}}, {2, {586, 587}}, {2, {586, 587}}, {2, {588, 589}}, {2, {588, 589}}, {2, {590, 591}}, {2, {590, 591}}, {2, {385, 595}}, {2, {390, 596}}, {2, {393, 598}}, {2, {394, 599}}, {2, {399, 601}}, {2, {400, 603}}, {2, {403, 608}}, {2, {404, 611}}, {2, {407, 616}}, {2, {406, 617}}, {2, {619, 11362}}, {2, {412, 623}}, {2, {413, 626}}, {2, {415, 629}}, {2, {637, 11364}}, {2, {422, 640}}, {2, {425, 643}}, {2, {430, 648}}, {2, {580, 649}}, {2, {433, 650}}, {2, {434, 651}}, {2, {581, 652}}, {2, {439, 658}}, {4, {837, 921, 953, 8126}}, {2, {891, 1021}}, {2, {892, 1022}}, {2, {893, 1023}}, {2, {902, 940}}, {2, {904, 941}}, {2, {905, 942}}, {2, {906, 943}}, {2, {908, 972}}, {2, {910, 973}}, {2, {911, 974}}, {2, {913, 945}}, {3, {914, 946, 976}}, {2, {915, 947}}, {2, {916, 948}}, {3, {917, 949, 1013}}, {2, {918, 950}}, {2, {919, 951}}, {3, {920, 952, 977}}, {4, {837, 921, 953, 8126}}, {3, {922, 954, 1008}}, {2, {923, 955}}, {3, {181, 924, 956}}, {2, {925, 957}}, {2, {926, 958}}, {2, {927, 959}}, {3, {928, 960, 982}}, {3, {929, 961, 1009}}, {2, {932, 964}}, {2, {933, 965}}, {3, {934, 966, 981}}, {2, {935, 967}}, {2, {936, 968}}, {2, {937, 969}}, {2, {938, 970}}, {2, {939, 971}}, {2, {902, 940}}, {2, {904, 941}}, {2, {905, 942}}, {2, {906, 943}}, {2, {913, 945}}, {3, {914, 946, 976}}, {2, {915, 947}}, {2, {916, 948}}, {3, {917, 949, 1013}}, {2, {918, 950}}, {2, {919, 951}}, {3, {920, 952, 977}}, {4, {837, 921, 953, 8126}}, {3, {922, 954, 1008}}, {2, {923, 955}}, {3, {181, 924, 956}}, {2, {925, 957}}, {2, {926, 958}}, {2, {927, 959}}, {3, {928, 960, 982}}, {3, {929, 961, 1009}}, {3, {931, 962, 963}}, {3, {931, 962, 963}}, {2, {932, 964}}, {2, {933, 965}}, {3, {934, 966, 981}}, {2, {935, 967}}, {2, {936, 968}}, {2, {937, 969}}, {2, {938, 970}}, {2, {939, 971}}, {2, {908, 972}}, {2, {910, 973}}, {2, {911, 974}}, {3, {914, 946, 976}}, {3, {920, 952, 977}}, {3, {934, 966, 981}}, {3, {928, 960, 982}}, {2, {984, 985}}, {2, {984, 985}}, {2, {986, 987}}, {2, {986, 987}}, {2, {988, 989}}, {2, {988, 989}}, {2, {990, 991}}, {2, {990, 991}}, {2, {992, 993}}, {2, {992, 993}}, {2, {994, 995}}, {2, {994, 995}}, {2, {996, 997}}, {2, {996, 997}}, {2, {998, 999}}, {2, {998, 999}}, {2, {1000, 1001}}, {2, {1000, 1001}}, {2, {1002, 1003}}, {2, {1002, 1003}}, {2, {1004, 1005}}, {2, {1004, 1005}}, {2, {1006, 1007}}, {2, {1006, 1007}}, {3, {922, 954, 1008}}, {3, {929, 961, 1009}}, {2, {1010, 1017}}, {3, {917, 949, 1013}}, {2, {1015, 1016}}, {2, {1015, 1016}}, {2, {1010, 1017}}, {2, {1018, 1019}}, {2, {1018, 1019}}, {2, {891, 1021}}, {2, {892, 1022}}, {2, {893, 1023}}, {2, {1024, 1104}}, {2, {1025, 1105}}, {2, {1026, 1106}}, {2, {1027, 1107}}, {2, {1028, 1108}}, {2, {1029, 1109}}, {2, {1030, 1110}}, {2, {1031, 1111}}, {2, {1032, 1112}}, {2, {1033, 1113}}, {2, {1034, 1114}}, {2, {1035, 1115}}, {2, {1036, 1116}}, {2, {1037, 1117}}, {2, {1038, 1118}}, {2, {1039, 1119}}, {2, {1040, 1072}}, {2, {1041, 1073}}, {2, {1042, 1074}}, {2, {1043, 1075}}, {2, {1044, 1076}}, {2, {1045, 1077}}, {2, {1046, 1078}}, {2, {1047, 1079}}, {2, {1048, 1080}}, {2, {1049, 1081}}, {2, {1050, 1082}}, {2, {1051, 1083}}, {2, {1052, 1084}}, {2, {1053, 1085}}, {2, {1054, 1086}}, {2, {1055, 1087}}, {2, {1056, 1088}}, {2, {1057, 1089}}, {2, {1058, 1090}}, {2, {1059, 1091}}, {2, {1060, 1092}}, {2, {1061, 1093}}, {2, {1062, 1094}}, {2, {1063, 1095}}, {2, {1064, 1096}}, {2, {1065, 1097}}, {2, {1066, 1098}}, {2, {1067, 1099}}, {2, {1068, 1100}}, {2, {1069, 1101}}, {2, {1070, 1102}}, {2, {1071, 1103}}, {2, {1040, 1072}}, {2, {1041, 1073}}, {2, {1042, 1074}}, {2, {1043, 1075}}, {2, {1044, 1076}}, {2, {1045, 1077}}, {2, {1046, 1078}}, {2, {1047, 1079}}, {2, {1048, 1080}}, {2, {1049, 1081}}, {2, {1050, 1082}}, {2, {1051, 1083}}, {2, {1052, 1084}}, {2, {1053, 1085}}, {2, {1054, 1086}}, {2, {1055, 1087}}, {2, {1056, 1088}}, {2, {1057, 1089}}, {2, {1058, 1090}}, {2, {1059, 1091}}, {2, {1060, 1092}}, {2, {1061, 1093}}, {2, {1062, 1094}}, {2, {1063, 1095}}, {2, {1064, 1096}}, {2, {1065, 1097}}, {2, {1066, 1098}}, {2, {1067, 1099}}, {2, {1068, 1100}}, {2, {1069, 1101}}, {2, {1070, 1102}}, {2, {1071, 1103}}, {2, {1024, 1104}}, {2, {1025, 1105}}, {2, {1026, 1106}}, {2, {1027, 1107}}, {2, {1028, 1108}}, {2, {1029, 1109}}, {2, {1030, 1110}}, {2, {1031, 1111}}, {2, {1032, 1112}}, {2, {1033, 1113}}, {2, {1034, 1114}}, {2, {1035, 1115}}, {2, {1036, 1116}}, {2, {1037, 1117}}, {2, {1038, 1118}}, {2, {1039, 1119}}, {2, {1120, 1121}}, {2, {1120, 1121}}, {2, {1122, 1123}}, {2, {1122, 1123}}, {2, {1124, 1125}}, {2, {1124, 1125}}, {2, {1126, 1127}}, {2, {1126, 1127}}, {2, {1128, 1129}}, {2, {1128, 1129}}, {2, {1130, 1131}}, {2, {1130, 1131}}, {2, {1132, 1133}}, {2, {1132, 1133}}, {2, {1134, 1135}}, {2, {1134, 1135}}, {2, {1136, 1137}}, {2, {1136, 1137}}, {2, {1138, 1139}}, {2, {1138, 1139}}, {2, {1140, 1141}}, {2, {1140, 1141}}, {2, {1142, 1143}}, {2, {1142, 1143}}, {2, {1144, 1145}}, {2, {1144, 1145}}, {2, {1146, 1147}}, {2, {1146, 1147}}, {2, {1148, 1149}}, {2, {1148, 1149}}, {2, {1150, 1151}}, {2, {1150, 1151}}, {2, {1152, 1153}}, {2, {1152, 1153}}, {2, {1162, 1163}}, {2, {1162, 1163}}, {2, {1164, 1165}}, {2, {1164, 1165}}, {2, {1166, 1167}}, {2, {1166, 1167}}, {2, {1168, 1169}}, {2, {1168, 1169}}, {2, {1170, 1171}}, {2, {1170, 1171}}, {2, {1172, 1173}}, {2, {1172, 1173}}, {2, {1174, 1175}}, {2, {1174, 1175}}, {2, {1176, 1177}}, {2, {1176, 1177}}, {2, {1178, 1179}}, {2, {1178, 1179}}, {2, {1180, 1181}}, {2, {1180, 1181}}, {2, {1182, 1183}}, {2, {1182, 1183}}, {2, {1184, 1185}}, {2, {1184, 1185}}, {2, {1186, 1187}}, {2, {1186, 1187}}, {2, {1188, 1189}}, {2, {1188, 1189}}, {2, {1190, 1191}}, {2, {1190, 1191}}, {2, {1192, 1193}}, {2, {1192, 1193}}, {2, {1194, 1195}}, {2, {1194, 1195}}, {2, {1196, 1197}}, {2, {1196, 1197}}, {2, {1198, 1199}}, {2, {1198, 1199}}, {2, {1200, 1201}}, {2, {1200, 1201}}, {2, {1202, 1203}}, {2, {1202, 1203}}, {2, {1204, 1205}}, {2, {1204, 1205}}, {2, {1206, 1207}}, {2, {1206, 1207}}, {2, {1208, 1209}}, {2, {1208, 1209}}, {2, {1210, 1211}}, {2, {1210, 1211}}, {2, {1212, 1213}}, {2, {1212, 1213}}, {2, {1214, 1215}}, {2, {1214, 1215}}, {2, {1216, 1231}}, {2, {1217, 1218}}, {2, {1217, 1218}}, {2, {1219, 1220}}, {2, {1219, 1220}}, {2, {1221, 1222}}, {2, {1221, 1222}}, {2, {1223, 1224}}, {2, {1223, 1224}}, {2, {1225, 1226}}, {2, {1225, 1226}}, {2, {1227, 1228}}, {2, {1227, 1228}}, {2, {1229, 1230}}, {2, {1229, 1230}}, {2, {1216, 1231}}, {2, {1232, 1233}}, {2, {1232, 1233}}, {2, {1234, 1235}}, {2, {1234, 1235}}, {2, {1236, 1237}}, {2, {1236, 1237}}, {2, {1238, 1239}}, {2, {1238, 1239}}, {2, {1240, 1241}}, {2, {1240, 1241}}, {2, {1242, 1243}}, {2, {1242, 1243}}, {2, {1244, 1245}}, {2, {1244, 1245}}, {2, {1246, 1247}}, {2, {1246, 1247}}, {2, {1248, 1249}}, {2, {1248, 1249}}, {2, {1250, 1251}}, {2, {1250, 1251}}, {2, {1252, 1253}}, {2, {1252, 1253}}, {2, {1254, 1255}}, {2, {1254, 1255}}, {2, {1256, 1257}}, {2, {1256, 1257}}, {2, {1258, 1259}}, {2, {1258, 1259}}, {2, {1260, 1261}}, {2, {1260, 1261}}, {2, {1262, 1263}}, {2, {1262, 1263}}, {2, {1264, 1265}}, {2, {1264, 1265}}, {2, {1266, 1267}}, {2, {1266, 1267}}, {2, {1268, 1269}}, {2, {1268, 1269}}, {2, {1270, 1271}}, {2, {1270, 1271}}, {2, {1272, 1273}}, {2, {1272, 1273}}, {2, {1274, 1275}}, {2, {1274, 1275}}, {2, {1276, 1277}}, {2, {1276, 1277}}, {2, {1278, 1279}}, {2, {1278, 1279}}, {2, {1280, 1281}}, {2, {1280, 1281}}, {2, {1282, 1283}}, {2, {1282, 1283}}, {2, {1284, 1285}}, {2, {1284, 1285}}, {2, {1286, 1287}}, {2, {1286, 1287}}, {2, {1288, 1289}}, {2, {1288, 1289}}, {2, {1290, 1291}}, {2, {1290, 1291}}, {2, {1292, 1293}}, {2, {1292, 1293}}, {2, {1294, 1295}}, {2, {1294, 1295}}, {2, {1296, 1297}}, {2, {1296, 1297}}, {2, {1298, 1299}}, {2, {1298, 1299}}, {2, {1329, 1377}}, {2, {1330, 1378}}, {2, {1331, 1379}}, {2, {1332, 1380}}, {2, {1333, 1381}}, {2, {1334, 1382}}, {2, {1335, 1383}}, {2, {1336, 1384}}, {2, {1337, 1385}}, {2, {1338, 1386}}, {2, {1339, 1387}}, {2, {1340, 1388}}, {2, {1341, 1389}}, {2, {1342, 1390}}, {2, {1343, 1391}}, {2, {1344, 1392}}, {2, {1345, 1393}}, {2, {1346, 1394}}, {2, {1347, 1395}}, {2, {1348, 1396}}, {2, {1349, 1397}}, {2, {1350, 1398}}, {2, {1351, 1399}}, {2, {1352, 1400}}, {2, {1353, 1401}}, {2, {1354, 1402}}, {2, {1355, 1403}}, {2, {1356, 1404}}, {2, {1357, 1405}}, {2, {1358, 1406}}, {2, {1359, 1407}}, {2, {1360, 1408}}, {2, {1361, 1409}}, {2, {1362, 1410}}, {2, {1363, 1411}}, {2, {1364, 1412}}, {2, {1365, 1413}}, {2, {1366, 1414}}, {2, {1329, 1377}}, {2, {1330, 1378}}, {2, {1331, 1379}}, {2, {1332, 1380}}, {2, {1333, 1381}}, {2, {1334, 1382}}, {2, {1335, 1383}}, {2, {1336, 1384}}, {2, {1337, 1385}}, {2, {1338, 1386}}, {2, {1339, 1387}}, {2, {1340, 1388}}, {2, {1341, 1389}}, {2, {1342, 1390}}, {2, {1343, 1391}}, {2, {1344, 1392}}, {2, {1345, 1393}}, {2, {1346, 1394}}, {2, {1347, 1395}}, {2, {1348, 1396}}, {2, {1349, 1397}}, {2, {1350, 1398}}, {2, {1351, 1399}}, {2, {1352, 1400}}, {2, {1353, 1401}}, {2, {1354, 1402}}, {2, {1355, 1403}}, {2, {1356, 1404}}, {2, {1357, 1405}}, {2, {1358, 1406}}, {2, {1359, 1407}}, {2, {1360, 1408}}, {2, {1361, 1409}}, {2, {1362, 1410}}, {2, {1363, 1411}}, {2, {1364, 1412}}, {2, {1365, 1413}}, {2, {1366, 1414}}, {2, {4256, 11520}}, {2, {4257, 11521}}, {2, {4258, 11522}}, {2, {4259, 11523}}, {2, {4260, 11524}}, {2, {4261, 11525}}, {2, {4262, 11526}}, {2, {4263, 11527}}, {2, {4264, 11528}}, {2, {4265, 11529}}, {2, {4266, 11530}}, {2, {4267, 11531}}, {2, {4268, 11532}}, {2, {4269, 11533}}, {2, {4270, 11534}}, {2, {4271, 11535}}, {2, {4272, 11536}}, {2, {4273, 11537}}, {2, {4274, 11538}}, {2, {4275, 11539}}, {2, {4276, 11540}}, {2, {4277, 11541}}, {2, {4278, 11542}}, {2, {4279, 11543}}, {2, {4280, 11544}}, {2, {4281, 11545}}, {2, {4282, 11546}}, {2, {4283, 11547}}, {2, {4284, 11548}}, {2, {4285, 11549}}, {2, {4286, 11550}}, {2, {4287, 11551}}, {2, {4288, 11552}}, {2, {4289, 11553}}, {2, {4290, 11554}}, {2, {4291, 11555}}, {2, {4292, 11556}}, {2, {4293, 11557}}, {2, {7549, 11363}}, {2, {7680, 7681}}, {2, {7680, 7681}}, {2, {7682, 7683}}, {2, {7682, 7683}}, {2, {7684, 7685}}, {2, {7684, 7685}}, {2, {7686, 7687}}, {2, {7686, 7687}}, {2, {7688, 7689}}, {2, {7688, 7689}}, {2, {7690, 7691}}, {2, {7690, 7691}}, {2, {7692, 7693}}, {2, {7692, 7693}}, {2, {7694, 7695}}, {2, {7694, 7695}}, {2, {7696, 7697}}, {2, {7696, 7697}}, {2, {7698, 7699}}, {2, {7698, 7699}}, {2, {7700, 7701}}, {2, {7700, 7701}}, {2, {7702, 7703}}, {2, {7702, 7703}}, {2, {7704, 7705}}, {2, {7704, 7705}}, {2, {7706, 7707}}, {2, {7706, 7707}}, {2, {7708, 7709}}, {2, {7708, 7709}}, {2, {7710, 7711}}, {2, {7710, 7711}}, {2, {7712, 7713}}, {2, {7712, 7713}}, {2, {7714, 7715}}, {2, {7714, 7715}}, {2, {7716, 7717}}, {2, {7716, 7717}}, {2, {7718, 7719}}, {2, {7718, 7719}}, {2, {7720, 7721}}, {2, {7720, 7721}}, {2, {7722, 7723}}, {2, {7722, 7723}}, {2, {7724, 7725}}, {2, {7724, 7725}}, {2, {7726, 7727}}, {2, {7726, 7727}}, {2, {7728, 7729}}, {2, {7728, 7729}}, {2, {7730, 7731}}, {2, {7730, 7731}}, {2, {7732, 7733}}, {2, {7732, 7733}}, {2, {7734, 7735}}, {2, {7734, 7735}}, {2, {7736, 7737}}, {2, {7736, 7737}}, {2, {7738, 7739}}, {2, {7738, 7739}}, {2, {7740, 7741}}, {2, {7740, 7741}}, {2, {7742, 7743}}, {2, {7742, 7743}}, {2, {7744, 7745}}, {2, {7744, 7745}}, {2, {7746, 7747}}, {2, {7746, 7747}}, {2, {7748, 7749}}, {2, {7748, 7749}}, {2, {7750, 7751}}, {2, {7750, 7751}}, {2, {7752, 7753}}, {2, {7752, 7753}}, {2, {7754, 7755}}, {2, {7754, 7755}}, {2, {7756, 7757}}, {2, {7756, 7757}}, {2, {7758, 7759}}, {2, {7758, 7759}}, {2, {7760, 7761}}, {2, {7760, 7761}}, {2, {7762, 7763}}, {2, {7762, 7763}}, {2, {7764, 7765}}, {2, {7764, 7765}}, {2, {7766, 7767}}, {2, {7766, 7767}}, {2, {7768, 7769}}, {2, {7768, 7769}}, {2, {7770, 7771}}, {2, {7770, 7771}}, {2, {7772, 7773}}, {2, {7772, 7773}}, {2, {7774, 7775}}, {2, {7774, 7775}}, {3, {7776, 7777, 7835}}, {3, {7776, 7777, 7835}}, {2, {7778, 7779}}, {2, {7778, 7779}}, {2, {7780, 7781}}, {2, {7780, 7781}}, {2, {7782, 7783}}, {2, {7782, 7783}}, {2, {7784, 7785}}, {2, {7784, 7785}}, {2, {7786, 7787}}, {2, {7786, 7787}}, {2, {7788, 7789}}, {2, {7788, 7789}}, {2, {7790, 7791}}, {2, {7790, 7791}}, {2, {7792, 7793}}, {2, {7792, 7793}}, {2, {7794, 7795}}, {2, {7794, 7795}}, {2, {7796, 7797}}, {2, {7796, 7797}}, {2, {7798, 7799}}, {2, {7798, 7799}}, {2, {7800, 7801}}, {2, {7800, 7801}}, {2, {7802, 7803}}, {2, {7802, 7803}}, {2, {7804, 7805}}, {2, {7804, 7805}}, {2, {7806, 7807}}, {2, {7806, 7807}}, {2, {7808, 7809}}, {2, {7808, 7809}}, {2, {7810, 7811}}, {2, {7810, 7811}}, {2, {7812, 7813}}, {2, {7812, 7813}}, {2, {7814, 7815}}, {2, {7814, 7815}}, {2, {7816, 7817}}, {2, {7816, 7817}}, {2, {7818, 7819}}, {2, {7818, 7819}}, {2, {7820, 7821}}, {2, {7820, 7821}}, {2, {7822, 7823}}, {2, {7822, 7823}}, {2, {7824, 7825}}, {2, {7824, 7825}}, {2, {7826, 7827}}, {2, {7826, 7827}}, {2, {7828, 7829}}, {2, {7828, 7829}}, {3, {7776, 7777, 7835}}, {2, {7840, 7841}}, {2, {7840, 7841}}, {2, {7842, 7843}}, {2, {7842, 7843}}, {2, {7844, 7845}}, {2, {7844, 7845}}, {2, {7846, 7847}}, {2, {7846, 7847}}, {2, {7848, 7849}}, {2, {7848, 7849}}, {2, {7850, 7851}}, {2, {7850, 7851}}, {2, {7852, 7853}}, {2, {7852, 7853}}, {2, {7854, 7855}}, {2, {7854, 7855}}, {2, {7856, 7857}}, {2, {7856, 7857}}, {2, {7858, 7859}}, {2, {7858, 7859}}, {2, {7860, 7861}}, {2, {7860, 7861}}, {2, {7862, 7863}}, {2, {7862, 7863}}, {2, {7864, 7865}}, {2, {7864, 7865}}, {2, {7866, 7867}}, {2, {7866, 7867}}, {2, {7868, 7869}}, {2, {7868, 7869}}, {2, {7870, 7871}}, {2, {7870, 7871}}, {2, {7872, 7873}}, {2, {7872, 7873}}, {2, {7874, 7875}}, {2, {7874, 7875}}, {2, {7876, 7877}}, {2, {7876, 7877}}, {2, {7878, 7879}}, {2, {7878, 7879}}, {2, {7880, 7881}}, {2, {7880, 7881}}, {2, {7882, 7883}}, {2, {7882, 7883}}, {2, {7884, 7885}}, {2, {7884, 7885}}, {2, {7886, 7887}}, {2, {7886, 7887}}, {2, {7888, 7889}}, {2, {7888, 7889}}, {2, {7890, 7891}}, {2, {7890, 7891}}, {2, {7892, 7893}}, {2, {7892, 7893}}, {2, {7894, 7895}}, {2, {7894, 7895}}, {2, {7896, 7897}}, {2, {7896, 7897}}, {2, {7898, 7899}}, {2, {7898, 7899}}, {2, {7900, 7901}}, {2, {7900, 7901}}, {2, {7902, 7903}}, {2, {7902, 7903}}, {2, {7904, 7905}}, {2, {7904, 7905}}, {2, {7906, 7907}}, {2, {7906, 7907}}, {2, {7908, 7909}}, {2, {7908, 7909}}, {2, {7910, 7911}}, {2, {7910, 7911}}, {2, {7912, 7913}}, {2, {7912, 7913}}, {2, {7914, 7915}}, {2, {7914, 7915}}, {2, {7916, 7917}}, {2, {7916, 7917}}, {2, {7918, 7919}}, {2, {7918, 7919}}, {2, {7920, 7921}}, {2, {7920, 7921}}, {2, {7922, 7923}}, {2, {7922, 7923}}, {2, {7924, 7925}}, {2, {7924, 7925}}, {2, {7926, 7927}}, {2, {7926, 7927}}, {2, {7928, 7929}}, {2, {7928, 7929}}, {2, {7936, 7944}}, {2, {7937, 7945}}, {2, {7938, 7946}}, {2, {7939, 7947}}, {2, {7940, 7948}}, {2, {7941, 7949}}, {2, {7942, 7950}}, {2, {7943, 7951}}, {2, {7936, 7944}}, {2, {7937, 7945}}, {2, {7938, 7946}}, {2, {7939, 7947}}, {2, {7940, 7948}}, {2, {7941, 7949}}, {2, {7942, 7950}}, {2, {7943, 7951}}, {2, {7952, 7960}}, {2, {7953, 7961}}, {2, {7954, 7962}}, {2, {7955, 7963}}, {2, {7956, 7964}}, {2, {7957, 7965}}, {2, {7952, 7960}}, {2, {7953, 7961}}, {2, {7954, 7962}}, {2, {7955, 7963}}, {2, {7956, 7964}}, {2, {7957, 7965}}, {2, {7968, 7976}}, {2, {7969, 7977}}, {2, {7970, 7978}}, {2, {7971, 7979}}, {2, {7972, 7980}}, {2, {7973, 7981}}, {2, {7974, 7982}}, {2, {7975, 7983}}, {2, {7968, 7976}}, {2, {7969, 7977}}, {2, {7970, 7978}}, {2, {7971, 7979}}, {2, {7972, 7980}}, {2, {7973, 7981}}, {2, {7974, 7982}}, {2, {7975, 7983}}, {2, {7984, 7992}}, {2, {7985, 7993}}, {2, {7986, 7994}}, {2, {7987, 7995}}, {2, {7988, 7996}}, {2, {7989, 7997}}, {2, {7990, 7998}}, {2, {7991, 7999}}, {2, {7984, 7992}}, {2, {7985, 7993}}, {2, {7986, 7994}}, {2, {7987, 7995}}, {2, {7988, 7996}}, {2, {7989, 7997}}, {2, {7990, 7998}}, {2, {7991, 7999}}, {2, {8000, 8008}}, {2, {8001, 8009}}, {2, {8002, 8010}}, {2, {8003, 8011}}, {2, {8004, 8012}}, {2, {8005, 8013}}, {2, {8000, 8008}}, {2, {8001, 8009}}, {2, {8002, 8010}}, {2, {8003, 8011}}, {2, {8004, 8012}}, {2, {8005, 8013}}, {2, {8017, 8025}}, {2, {8019, 8027}}, {2, {8021, 8029}}, {2, {8023, 8031}}, {2, {8017, 8025}}, {2, {8019, 8027}}, {2, {8021, 8029}}, {2, {8023, 8031}}, {2, {8032, 8040}}, {2, {8033, 8041}}, {2, {8034, 8042}}, {2, {8035, 8043}}, {2, {8036, 8044}}, {2, {8037, 8045}}, {2, {8038, 8046}}, {2, {8039, 8047}}, {2, {8032, 8040}}, {2, {8033, 8041}}, {2, {8034, 8042}}, {2, {8035, 8043}}, {2, {8036, 8044}}, {2, {8037, 8045}}, {2, {8038, 8046}}, {2, {8039, 8047}}, {2, {8048, 8122}}, {2, {8049, 8123}}, {2, {8050, 8136}}, {2, {8051, 8137}}, {2, {8052, 8138}}, {2, {8053, 8139}}, {2, {8054, 8154}}, {2, {8055, 8155}}, {2, {8056, 8184}}, {2, {8057, 8185}}, {2, {8058, 8170}}, {2, {8059, 8171}}, {2, {8060, 8186}}, {2, {8061, 8187}}, {2, {8112, 8120}}, {2, {8113, 8121}}, {2, {8112, 8120}}, {2, {8113, 8121}}, {2, {8048, 8122}}, {2, {8049, 8123}}, {4, {837, 921, 953, 8126}}, {2, {8050, 8136}}, {2, {8051, 8137}}, {2, {8052, 8138}}, {2, {8053, 8139}}, {2, {8144, 8152}}, {2, {8145, 8153}}, {2, {8144, 8152}}, {2, {8145, 8153}}, {2, {8054, 8154}}, {2, {8055, 8155}}, {2, {8160, 8168}}, {2, {8161, 8169}}, {2, {8165, 8172}}, {2, {8160, 8168}}, {2, {8161, 8169}}, {2, {8058, 8170}}, {2, {8059, 8171}}, {2, {8165, 8172}}, {2, {8056, 8184}}, {2, {8057, 8185}}, {2, {8060, 8186}}, {2, {8061, 8187}}, {2, {8498, 8526}}, {2, {8498, 8526}}, {2, {8544, 8560}}, {2, {8545, 8561}}, {2, {8546, 8562}}, {2, {8547, 8563}}, {2, {8548, 8564}}, {2, {8549, 8565}}, {2, {8550, 8566}}, {2, {8551, 8567}}, {2, {8552, 8568}}, {2, {8553, 8569}}, {2, {8554, 8570}}, {2, {8555, 8571}}, {2, {8556, 8572}}, {2, {8557, 8573}}, {2, {8558, 8574}}, {2, {8559, 8575}}, {2, {8544, 8560}}, {2, {8545, 8561}}, {2, {8546, 8562}}, {2, {8547, 8563}}, {2, {8548, 8564}}, {2, {8549, 8565}}, {2, {8550, 8566}}, {2, {8551, 8567}}, {2, {8552, 8568}}, {2, {8553, 8569}}, {2, {8554, 8570}}, {2, {8555, 8571}}, {2, {8556, 8572}}, {2, {8557, 8573}}, {2, {8558, 8574}}, {2, {8559, 8575}}, {2, {8579, 8580}}, {2, {8579, 8580}}, {2, {9398, 9424}}, {2, {9399, 9425}}, {2, {9400, 9426}}, {2, {9401, 9427}}, {2, {9402, 9428}}, {2, {9403, 9429}}, {2, {9404, 9430}}, {2, {9405, 9431}}, {2, {9406, 9432}}, {2, {9407, 9433}}, {2, {9408, 9434}}, {2, {9409, 9435}}, {2, {9410, 9436}}, {2, {9411, 9437}}, {2, {9412, 9438}}, {2, {9413, 9439}}, {2, {9414, 9440}}, {2, {9415, 9441}}, {2, {9416, 9442}}, {2, {9417, 9443}}, {2, {9418, 9444}}, {2, {9419, 9445}}, {2, {9420, 9446}}, {2, {9421, 9447}}, {2, {9422, 9448}}, {2, {9423, 9449}}, {2, {9398, 9424}}, {2, {9399, 9425}}, {2, {9400, 9426}}, {2, {9401, 9427}}, {2, {9402, 9428}}, {2, {9403, 9429}}, {2, {9404, 9430}}, {2, {9405, 9431}}, {2, {9406, 9432}}, {2, {9407, 9433}}, {2, {9408, 9434}}, {2, {9409, 9435}}, {2, {9410, 9436}}, {2, {9411, 9437}}, {2, {9412, 9438}}, {2, {9413, 9439}}, {2, {9414, 9440}}, {2, {9415, 9441}}, {2, {9416, 9442}}, {2, {9417, 9443}}, {2, {9418, 9444}}, {2, {9419, 9445}}, {2, {9420, 9446}}, {2, {9421, 9447}}, {2, {9422, 9448}}, {2, {9423, 9449}}, {2, {11264, 11312}}, {2, {11265, 11313}}, {2, {11266, 11314}}, {2, {11267, 11315}}, {2, {11268, 11316}}, {2, {11269, 11317}}, {2, {11270, 11318}}, {2, {11271, 11319}}, {2, {11272, 11320}}, {2, {11273, 11321}}, {2, {11274, 11322}}, {2, {11275, 11323}}, {2, {11276, 11324}}, {2, {11277, 11325}}, {2, {11278, 11326}}, {2, {11279, 11327}}, {2, {11280, 11328}}, {2, {11281, 11329}}, {2, {11282, 11330}}, {2, {11283, 11331}}, {2, {11284, 11332}}, {2, {11285, 11333}}, {2, {11286, 11334}}, {2, {11287, 11335}}, {2, {11288, 11336}}, {2, {11289, 11337}}, {2, {11290, 11338}}, {2, {11291, 11339}}, {2, {11292, 11340}}, {2, {11293, 11341}}, {2, {11294, 11342}}, {2, {11295, 11343}}, {2, {11296, 11344}}, {2, {11297, 11345}}, {2, {11298, 11346}}, {2, {11299, 11347}}, {2, {11300, 11348}}, {2, {11301, 11349}}, {2, {11302, 11350}}, {2, {11303, 11351}}, {2, {11304, 11352}}, {2, {11305, 11353}}, {2, {11306, 11354}}, {2, {11307, 11355}}, {2, {11308, 11356}}, {2, {11309, 11357}}, {2, {11310, 11358}}, {2, {11264, 11312}}, {2, {11265, 11313}}, {2, {11266, 11314}}, {2, {11267, 11315}}, {2, {11268, 11316}}, {2, {11269, 11317}}, {2, {11270, 11318}}, {2, {11271, 11319}}, {2, {11272, 11320}}, {2, {11273, 11321}}, {2, {11274, 11322}}, {2, {11275, 11323}}, {2, {11276, 11324}}, {2, {11277, 11325}}, {2, {11278, 11326}}, {2, {11279, 11327}}, {2, {11280, 11328}}, {2, {11281, 11329}}, {2, {11282, 11330}}, {2, {11283, 11331}}, {2, {11284, 11332}}, {2, {11285, 11333}}, {2, {11286, 11334}}, {2, {11287, 11335}}, {2, {11288, 11336}}, {2, {11289, 11337}}, {2, {11290, 11338}}, {2, {11291, 11339}}, {2, {11292, 11340}}, {2, {11293, 11341}}, {2, {11294, 11342}}, {2, {11295, 11343}}, {2, {11296, 11344}}, {2, {11297, 11345}}, {2, {11298, 11346}}, {2, {11299, 11347}}, {2, {11300, 11348}}, {2, {11301, 11349}}, {2, {11302, 11350}}, {2, {11303, 11351}}, {2, {11304, 11352}}, {2, {11305, 11353}}, {2, {11306, 11354}}, {2, {11307, 11355}}, {2, {11308, 11356}}, {2, {11309, 11357}}, {2, {11310, 11358}}, {2, {11360, 11361}}, {2, {11360, 11361}}, {2, {619, 11362}}, {2, {7549, 11363}}, {2, {637, 11364}}, {2, {570, 11365}}, {2, {574, 11366}}, {2, {11367, 11368}}, {2, {11367, 11368}}, {2, {11369, 11370}}, {2, {11369, 11370}}, {2, {11371, 11372}}, {2, {11371, 11372}}, {2, {11381, 11382}}, {2, {11381, 11382}}, {2, {11392, 11393}}, {2, {11392, 11393}}, {2, {11394, 11395}}, {2, {11394, 11395}}, {2, {11396, 11397}}, {2, {11396, 11397}}, {2, {11398, 11399}}, {2, {11398, 11399}}, {2, {11400, 11401}}, {2, {11400, 11401}}, {2, {11402, 11403}}, {2, {11402, 11403}}, {2, {11404, 11405}}, {2, {11404, 11405}}, {2, {11406, 11407}}, {2, {11406, 11407}}, {2, {11408, 11409}}, {2, {11408, 11409}}, {2, {11410, 11411}}, {2, {11410, 11411}}, {2, {11412, 11413}}, {2, {11412, 11413}}, {2, {11414, 11415}}, {2, {11414, 11415}}, {2, {11416, 11417}}, {2, {11416, 11417}}, {2, {11418, 11419}}, {2, {11418, 11419}}, {2, {11420, 11421}}, {2, {11420, 11421}}, {2, {11422, 11423}}, {2, {11422, 11423}}, {2, {11424, 11425}}, {2, {11424, 11425}}, {2, {11426, 11427}}, {2, {11426, 11427}}, {2, {11428, 11429}}, {2, {11428, 11429}}, {2, {11430, 11431}}, {2, {11430, 11431}}, {2, {11432, 11433}}, {2, {11432, 11433}}, {2, {11434, 11435}}, {2, {11434, 11435}}, {2, {11436, 11437}}, {2, {11436, 11437}}, {2, {11438, 11439}}, {2, {11438, 11439}}, {2, {11440, 11441}}, {2, {11440, 11441}}, {2, {11442, 11443}}, {2, {11442, 11443}}, {2, {11444, 11445}}, {2, {11444, 11445}}, {2, {11446, 11447}}, {2, {11446, 11447}}, {2, {11448, 11449}}, {2, {11448, 11449}}, {2, {11450, 11451}}, {2, {11450, 11451}}, {2, {11452, 11453}}, {2, {11452, 11453}}, {2, {11454, 11455}}, {2, {11454, 11455}}, {2, {11456, 11457}}, {2, {11456, 11457}}, {2, {11458, 11459}}, {2, {11458, 11459}}, {2, {11460, 11461}}, {2, {11460, 11461}}, {2, {11462, 11463}}, {2, {11462, 11463}}, {2, {11464, 11465}}, {2, {11464, 11465}}, {2, {11466, 11467}}, {2, {11466, 11467}}, {2, {11468, 11469}}, {2, {11468, 11469}}, {2, {11470, 11471}}, {2, {11470, 11471}}, {2, {11472, 11473}}, {2, {11472, 11473}}, {2, {11474, 11475}}, {2, {11474, 11475}}, {2, {11476, 11477}}, {2, {11476, 11477}}, {2, {11478, 11479}}, {2, {11478, 11479}}, {2, {11480, 11481}}, {2, {11480, 11481}}, {2, {11482, 11483}}, {2, {11482, 11483}}, {2, {11484, 11485}}, {2, {11484, 11485}}, {2, {11486, 11487}}, {2, {11486, 11487}}, {2, {11488, 11489}}, {2, {11488, 11489}}, {2, {11490, 11491}}, {2, {11490, 11491}}, {2, {4256, 11520}}, {2, {4257, 11521}}, {2, {4258, 11522}}, {2, {4259, 11523}}, {2, {4260, 11524}}, {2, {4261, 11525}}, {2, {4262, 11526}}, {2, {4263, 11527}}, {2, {4264, 11528}}, {2, {4265, 11529}}, {2, {4266, 11530}}, {2, {4267, 11531}}, {2, {4268, 11532}}, {2, {4269, 11533}}, {2, {4270, 11534}}, {2, {4271, 11535}}, {2, {4272, 11536}}, {2, {4273, 11537}}, {2, {4274, 11538}}, {2, {4275, 11539}}, {2, {4276, 11540}}, {2, {4277, 11541}}, {2, {4278, 11542}}, {2, {4279, 11543}}, {2, {4280, 11544}}, {2, {4281, 11545}}, {2, {4282, 11546}}, {2, {4283, 11547}}, {2, {4284, 11548}}, {2, {4285, 11549}}, {2, {4286, 11550}}, {2, {4287, 11551}}, {2, {4288, 11552}}, {2, {4289, 11553}}, {2, {4290, 11554}}, {2, {4291, 11555}}, {2, {4292, 11556}}, {2, {4293, 11557}}, {0, {0}} }; // NOLINT
+static const uint16_t kEcma262UnCanonicalizeTable0Size = 1656;
+static const int32_t kEcma262UnCanonicalizeTable0[3312] = { 65, 1, 66, 5, 67, 9, 68, 13, 69, 17, 70, 21, 71, 25, 72, 29, 73, 33, 74, 37, 75, 41, 76, 45, 77, 49, 78, 53, 79, 57, 80, 61, 81, 65, 82, 69, 83, 73, 84, 77, 85, 81, 86, 85, 87, 89, 88, 93, 89, 97, 90, 101, 97, 105, 98, 109, 99, 113, 100, 117, 101, 121, 102, 125, 103, 129, 104, 133, 105, 137, 106, 141, 107, 145, 108, 149, 109, 153, 110, 157, 111, 161, 112, 165, 113, 169, 114, 173, 115, 177, 116, 181, 117, 185, 118, 189, 119, 193, 120, 197, 121, 201, 122, 205, 181, 209, 192, 213, 193, 217, 194, 221, 195, 225, 196, 229, 197, 233, 198, 237, 199, 241, 200, 245, 201, 249, 202, 253, 203, 257, 204, 261, 205, 265, 206, 269, 207, 273, 208, 277, 209, 281, 210, 285, 211, 289, 212, 293, 213, 297, 214, 301, 216, 305, 217, 309, 218, 313, 219, 317, 220, 321, 221, 325, 222, 329, 224, 333, 225, 337, 226, 341, 227, 345, 228, 349, 229, 353, 230, 357, 231, 361, 232, 365, 233, 369, 234, 373, 235, 377, 236, 381, 237, 385, 238, 389, 239, 393, 240, 397, 241, 401, 242, 405, 243, 409, 244, 413, 245, 417, 246, 421, 248, 425, 249, 429, 250, 433, 251, 437, 252, 441, 253, 445, 254, 449, 255, 453, 256, 457, 257, 461, 258, 465, 259, 469, 260, 473, 261, 477, 262, 481, 263, 485, 264, 489, 265, 493, 266, 497, 267, 501, 268, 505, 269, 509, 270, 513, 271, 517, 272, 521, 273, 525, 274, 529, 275, 533, 276, 537, 277, 541, 278, 545, 279, 549, 280, 553, 281, 557, 282, 561, 283, 565, 284, 569, 285, 573, 286, 577, 287, 581, 288, 585, 289, 589, 290, 593, 291, 597, 292, 601, 293, 605, 294, 609, 295, 613, 296, 617, 297, 621, 298, 625, 299, 629, 300, 633, 301, 637, 302, 641, 303, 645, 306, 649, 307, 653, 308, 657, 309, 661, 310, 665, 311, 669, 313, 673, 314, 677, 315, 681, 316, 685, 317, 689, 318, 693, 319, 697, 320, 701, 321, 705, 322, 709, 323, 713, 324, 717, 325, 721, 326, 725, 327, 729, 328, 733, 330, 737, 331, 741, 332, 745, 333, 749, 334, 753, 335, 757, 336, 761, 337, 765, 338, 769, 339, 773, 340, 777, 341, 781, 342, 785, 343, 789, 344, 793, 345, 797, 346, 801, 347, 805, 348, 809, 349, 813, 350, 817, 351, 821, 352, 825, 353, 829, 354, 833, 355, 837, 356, 841, 357, 845, 358, 849, 359, 853, 360, 857, 361, 861, 362, 865, 363, 869, 364, 873, 365, 877, 366, 881, 367, 885, 368, 889, 369, 893, 370, 897, 371, 901, 372, 905, 373, 909, 374, 913, 375, 917, 376, 921, 377, 925, 378, 929, 379, 933, 380, 937, 381, 941, 382, 945, 384, 949, 385, 953, 386, 957, 387, 961, 388, 965, 389, 969, 390, 973, 391, 977, 392, 981, 393, 985, 394, 989, 395, 993, 396, 997, 398, 1001, 399, 1005, 400, 1009, 401, 1013, 402, 1017, 403, 1021, 404, 1025, 405, 1029, 406, 1033, 407, 1037, 408, 1041, 409, 1045, 410, 1049, 412, 1053, 413, 1057, 414, 1061, 415, 1065, 416, 1069, 417, 1073, 418, 1077, 419, 1081, 420, 1085, 421, 1089, 422, 1093, 423, 1097, 424, 1101, 425, 1105, 428, 1109, 429, 1113, 430, 1117, 431, 1121, 432, 1125, 433, 1129, 434, 1133, 435, 1137, 436, 1141, 437, 1145, 438, 1149, 439, 1153, 440, 1157, 441, 1161, 444, 1165, 445, 1169, 447, 1173, 452, 1177, 453, 1181, 454, 1185, 455, 1189, 456, 1193, 457, 1197, 458, 1201, 459, 1205, 460, 1209, 461, 1213, 462, 1217, 463, 1221, 464, 1225, 465, 1229, 466, 1233, 467, 1237, 468, 1241, 469, 1245, 470, 1249, 471, 1253, 472, 1257, 473, 1261, 474, 1265, 475, 1269, 476, 1273, 477, 1277, 478, 1281, 479, 1285, 480, 1289, 481, 1293, 482, 1297, 483, 1301, 484, 1305, 485, 1309, 486, 1313, 487, 1317, 488, 1321, 489, 1325, 490, 1329, 491, 1333, 492, 1337, 493, 1341, 494, 1345, 495, 1349, 497, 1353, 498, 1357, 499, 1361, 500, 1365, 501, 1369, 502, 1373, 503, 1377, 504, 1381, 505, 1385, 506, 1389, 507, 1393, 508, 1397, 509, 1401, 510, 1405, 511, 1409, 512, 1413, 513, 1417, 514, 1421, 515, 1425, 516, 1429, 517, 1433, 518, 1437, 519, 1441, 520, 1445, 521, 1449, 522, 1453, 523, 1457, 524, 1461, 525, 1465, 526, 1469, 527, 1473, 528, 1477, 529, 1481, 530, 1485, 531, 1489, 532, 1493, 533, 1497, 534, 1501, 535, 1505, 536, 1509, 537, 1513, 538, 1517, 539, 1521, 540, 1525, 541, 1529, 542, 1533, 543, 1537, 544, 1541, 546, 1545, 547, 1549, 548, 1553, 549, 1557, 550, 1561, 551, 1565, 552, 1569, 553, 1573, 554, 1577, 555, 1581, 556, 1585, 557, 1589, 558, 1593, 559, 1597, 560, 1601, 561, 1605, 562, 1609, 563, 1613, 570, 1617, 571, 1621, 572, 1625, 573, 1629, 574, 1633, 577, 1637, 578, 1641, 579, 1645, 580, 1649, 581, 1653, 582, 1657, 583, 1661, 584, 1665, 585, 1669, 586, 1673, 587, 1677, 588, 1681, 589, 1685, 590, 1689, 591, 1693, 595, 1697, 596, 1701, 598, 1705, 599, 1709, 601, 1713, 603, 1717, 608, 1721, 611, 1725, 616, 1729, 617, 1733, 619, 1737, 623, 1741, 626, 1745, 629, 1749, 637, 1753, 640, 1757, 643, 1761, 648, 1765, 649, 1769, 650, 1773, 651, 1777, 652, 1781, 658, 1785, 837, 1789, 891, 1793, 892, 1797, 893, 1801, 902, 1805, 904, 1809, 905, 1813, 906, 1817, 908, 1821, 910, 1825, 911, 1829, 913, 1833, 914, 1837, 915, 1841, 916, 1845, 917, 1849, 918, 1853, 919, 1857, 920, 1861, 921, 1865, 922, 1869, 923, 1873, 924, 1877, 925, 1881, 926, 1885, 927, 1889, 928, 1893, 929, 1897, 931, 6, 932, 1901, 933, 1905, 934, 1909, 935, 1913, 936, 1917, 937, 1921, 938, 1925, 939, 1929, 940, 1933, 941, 1937, 942, 1941, 943, 1945, 945, 1949, 946, 1953, 947, 1957, 948, 1961, 949, 1965, 950, 1969, 951, 1973, 952, 1977, 953, 1981, 954, 1985, 955, 1989, 956, 1993, 957, 1997, 958, 2001, 959, 2005, 960, 2009, 961, 2013, 962, 2017, 963, 2021, 964, 2025, 965, 2029, 966, 2033, 967, 2037, 968, 2041, 969, 2045, 970, 2049, 971, 2053, 972, 2057, 973, 2061, 974, 2065, 976, 2069, 977, 2073, 981, 2077, 982, 2081, 984, 2085, 985, 2089, 986, 2093, 987, 2097, 988, 2101, 989, 2105, 990, 2109, 991, 2113, 992, 2117, 993, 2121, 994, 2125, 995, 2129, 996, 2133, 997, 2137, 998, 2141, 999, 2145, 1000, 2149, 1001, 2153, 1002, 2157, 1003, 2161, 1004, 2165, 1005, 2169, 1006, 2173, 1007, 2177, 1008, 2181, 1009, 2185, 1010, 2189, 1013, 2193, 1015, 2197, 1016, 2201, 1017, 2205, 1018, 2209, 1019, 2213, 1021, 2217, 1022, 2221, 1023, 2225, 1024, 2229, 1025, 2233, 1026, 2237, 1027, 2241, 1028, 2245, 1029, 2249, 1030, 2253, 1031, 2257, 1032, 2261, 1033, 2265, 1034, 2269, 1035, 2273, 1036, 2277, 1037, 2281, 1038, 2285, 1039, 2289, 1040, 2293, 1041, 2297, 1042, 2301, 1043, 2305, 1044, 2309, 1045, 2313, 1046, 2317, 1047, 2321, 1048, 2325, 1049, 2329, 1050, 2333, 1051, 2337, 1052, 2341, 1053, 2345, 1054, 2349, 1055, 2353, 1056, 2357, 1057, 2361, 1058, 2365, 1059, 2369, 1060, 2373, 1061, 2377, 1062, 2381, 1063, 2385, 1064, 2389, 1065, 2393, 1066, 2397, 1067, 2401, 1068, 2405, 1069, 2409, 1070, 2413, 1071, 2417, 1072, 2421, 1073, 2425, 1074, 2429, 1075, 2433, 1076, 2437, 1077, 2441, 1078, 2445, 1079, 2449, 1080, 2453, 1081, 2457, 1082, 2461, 1083, 2465, 1084, 2469, 1085, 2473, 1086, 2477, 1087, 2481, 1088, 2485, 1089, 2489, 1090, 2493, 1091, 2497, 1092, 2501, 1093, 2505, 1094, 2509, 1095, 2513, 1096, 2517, 1097, 2521, 1098, 2525, 1099, 2529, 1100, 2533, 1101, 2537, 1102, 2541, 1103, 2545, 1104, 2549, 1105, 2553, 1106, 2557, 1107, 2561, 1108, 2565, 1109, 2569, 1110, 2573, 1111, 2577, 1112, 2581, 1113, 2585, 1114, 2589, 1115, 2593, 1116, 2597, 1117, 2601, 1118, 2605, 1119, 2609, 1120, 2613, 1121, 2617, 1122, 2621, 1123, 2625, 1124, 2629, 1125, 2633, 1126, 2637, 1127, 2641, 1128, 2645, 1129, 2649, 1130, 2653, 1131, 2657, 1132, 2661, 1133, 2665, 1134, 2669, 1135, 2673, 1136, 2677, 1137, 2681, 1138, 2685, 1139, 2689, 1140, 2693, 1141, 2697, 1142, 2701, 1143, 2705, 1144, 2709, 1145, 2713, 1146, 2717, 1147, 2721, 1148, 2725, 1149, 2729, 1150, 2733, 1151, 2737, 1152, 2741, 1153, 2745, 1162, 2749, 1163, 2753, 1164, 2757, 1165, 2761, 1166, 2765, 1167, 2769, 1168, 2773, 1169, 2777, 1170, 2781, 1171, 2785, 1172, 2789, 1173, 2793, 1174, 2797, 1175, 2801, 1176, 2805, 1177, 2809, 1178, 2813, 1179, 2817, 1180, 2821, 1181, 2825, 1182, 2829, 1183, 2833, 1184, 2837, 1185, 2841, 1186, 2845, 1187, 2849, 1188, 2853, 1189, 2857, 1190, 2861, 1191, 2865, 1192, 2869, 1193, 2873, 1194, 2877, 1195, 2881, 1196, 2885, 1197, 2889, 1198, 2893, 1199, 2897, 1200, 2901, 1201, 2905, 1202, 2909, 1203, 2913, 1204, 2917, 1205, 2921, 1206, 2925, 1207, 2929, 1208, 2933, 1209, 2937, 1210, 2941, 1211, 2945, 1212, 2949, 1213, 2953, 1214, 2957, 1215, 2961, 1216, 2965, 1217, 2969, 1218, 2973, 1219, 2977, 1220, 2981, 1221, 2985, 1222, 2989, 1223, 2993, 1224, 2997, 1225, 3001, 1226, 3005, 1227, 3009, 1228, 3013, 1229, 3017, 1230, 3021, 1231, 3025, 1232, 3029, 1233, 3033, 1234, 3037, 1235, 3041, 1236, 3045, 1237, 3049, 1238, 3053, 1239, 3057, 1240, 3061, 1241, 3065, 1242, 3069, 1243, 3073, 1244, 3077, 1245, 3081, 1246, 3085, 1247, 3089, 1248, 3093, 1249, 3097, 1250, 3101, 1251, 3105, 1252, 3109, 1253, 3113, 1254, 3117, 1255, 3121, 1256, 3125, 1257, 3129, 1258, 3133, 1259, 3137, 1260, 3141, 1261, 3145, 1262, 3149, 1263, 3153, 1264, 3157, 1265, 3161, 1266, 3165, 1267, 3169, 1268, 3173, 1269, 3177, 1270, 3181, 1271, 3185, 1272, 3189, 1273, 3193, 1274, 3197, 1275, 3201, 1276, 3205, 1277, 3209, 1278, 3213, 1279, 3217, 1280, 3221, 1281, 3225, 1282, 3229, 1283, 3233, 1284, 3237, 1285, 3241, 1286, 3245, 1287, 3249, 1288, 3253, 1289, 3257, 1290, 3261, 1291, 3265, 1292, 3269, 1293, 3273, 1294, 3277, 1295, 3281, 1296, 3285, 1297, 3289, 1298, 3293, 1299, 3297, 1329, 3301, 1330, 3305, 1331, 3309, 1332, 3313, 1333, 3317, 1334, 3321, 1335, 3325, 1336, 3329, 1337, 3333, 1338, 3337, 1339, 3341, 1340, 3345, 1341, 3349, 1342, 3353, 1343, 3357, 1344, 3361, 1345, 3365, 1346, 3369, 1347, 3373, 1348, 3377, 1349, 3381, 1350, 3385, 1351, 3389, 1352, 3393, 1353, 3397, 1354, 3401, 1355, 3405, 1356, 3409, 1357, 3413, 1358, 3417, 1359, 3421, 1360, 3425, 1361, 3429, 1362, 3433, 1363, 3437, 1364, 3441, 1365, 3445, 1366, 3449, 1377, 3453, 1378, 3457, 1379, 3461, 1380, 3465, 1381, 3469, 1382, 3473, 1383, 3477, 1384, 3481, 1385, 3485, 1386, 3489, 1387, 3493, 1388, 3497, 1389, 3501, 1390, 3505, 1391, 3509, 1392, 3513, 1393, 3517, 1394, 3521, 1395, 3525, 1396, 3529, 1397, 3533, 1398, 3537, 1399, 3541, 1400, 3545, 1401, 3549, 1402, 3553, 1403, 3557, 1404, 3561, 1405, 3565, 1406, 3569, 1407, 3573, 1408, 3577, 1409, 3581, 1410, 3585, 1411, 3589, 1412, 3593, 1413, 3597, 1414, 3601, 4256, 3605, 4257, 3609, 4258, 3613, 4259, 3617, 4260, 3621, 4261, 3625, 4262, 3629, 4263, 3633, 4264, 3637, 4265, 3641, 4266, 3645, 4267, 3649, 4268, 3653, 4269, 3657, 4270, 3661, 4271, 3665, 4272, 3669, 4273, 3673, 4274, 3677, 4275, 3681, 4276, 3685, 4277, 3689, 4278, 3693, 4279, 3697, 4280, 3701, 4281, 3705, 4282, 3709, 4283, 3713, 4284, 3717, 4285, 3721, 4286, 3725, 4287, 3729, 4288, 3733, 4289, 3737, 4290, 3741, 4291, 3745, 4292, 3749, 4293, 3753, 7549, 3757, 7680, 3761, 7681, 3765, 7682, 3769, 7683, 3773, 7684, 3777, 7685, 3781, 7686, 3785, 7687, 3789, 7688, 3793, 7689, 3797, 7690, 3801, 7691, 3805, 7692, 3809, 7693, 3813, 7694, 3817, 7695, 3821, 7696, 3825, 7697, 3829, 7698, 3833, 7699, 3837, 7700, 3841, 7701, 3845, 7702, 3849, 7703, 3853, 7704, 3857, 7705, 3861, 7706, 3865, 7707, 3869, 7708, 3873, 7709, 3877, 7710, 3881, 7711, 3885, 7712, 3889, 7713, 3893, 7714, 3897, 7715, 3901, 7716, 3905, 7717, 3909, 7718, 3913, 7719, 3917, 7720, 3921, 7721, 3925, 7722, 3929, 7723, 3933, 7724, 3937, 7725, 3941, 7726, 3945, 7727, 3949, 7728, 3953, 7729, 3957, 7730, 3961, 7731, 3965, 7732, 3969, 7733, 3973, 7734, 3977, 7735, 3981, 7736, 3985, 7737, 3989, 7738, 3993, 7739, 3997, 7740, 4001, 7741, 4005, 7742, 4009, 7743, 4013, 7744, 4017, 7745, 4021, 7746, 4025, 7747, 4029, 7748, 4033, 7749, 4037, 7750, 4041, 7751, 4045, 7752, 4049, 7753, 4053, 7754, 4057, 7755, 4061, 7756, 4065, 7757, 4069, 7758, 4073, 7759, 4077, 7760, 4081, 7761, 4085, 7762, 4089, 7763, 4093, 7764, 4097, 7765, 4101, 7766, 4105, 7767, 4109, 7768, 4113, 7769, 4117, 7770, 4121, 7771, 4125, 7772, 4129, 7773, 4133, 7774, 4137, 7775, 4141, 7776, 4145, 7777, 4149, 7778, 4153, 7779, 4157, 7780, 4161, 7781, 4165, 7782, 4169, 7783, 4173, 7784, 4177, 7785, 4181, 7786, 4185, 7787, 4189, 7788, 4193, 7789, 4197, 7790, 4201, 7791, 4205, 7792, 4209, 7793, 4213, 7794, 4217, 7795, 4221, 7796, 4225, 7797, 4229, 7798, 4233, 7799, 4237, 7800, 4241, 7801, 4245, 7802, 4249, 7803, 4253, 7804, 4257, 7805, 4261, 7806, 4265, 7807, 4269, 7808, 4273, 7809, 4277, 7810, 4281, 7811, 4285, 7812, 4289, 7813, 4293, 7814, 4297, 7815, 4301, 7816, 4305, 7817, 4309, 7818, 4313, 7819, 4317, 7820, 4321, 7821, 4325, 7822, 4329, 7823, 4333, 7824, 4337, 7825, 4341, 7826, 4345, 7827, 4349, 7828, 4353, 7829, 4357, 7835, 4361, 7840, 4365, 7841, 4369, 7842, 4373, 7843, 4377, 7844, 4381, 7845, 4385, 7846, 4389, 7847, 4393, 7848, 4397, 7849, 4401, 7850, 4405, 7851, 4409, 7852, 4413, 7853, 4417, 7854, 4421, 7855, 4425, 7856, 4429, 7857, 4433, 7858, 4437, 7859, 4441, 7860, 4445, 7861, 4449, 7862, 4453, 7863, 4457, 7864, 4461, 7865, 4465, 7866, 4469, 7867, 4473, 7868, 4477, 7869, 4481, 7870, 4485, 7871, 4489, 7872, 4493, 7873, 4497, 7874, 4501, 7875, 4505, 7876, 4509, 7877, 4513, 7878, 4517, 7879, 4521, 7880, 4525, 7881, 4529, 7882, 4533, 7883, 4537, 7884, 4541, 7885, 4545, 7886, 4549, 7887, 4553, 7888, 4557, 7889, 4561, 7890, 4565, 7891, 4569, 7892, 4573, 7893, 4577, 7894, 4581, 7895, 4585, 7896, 4589, 7897, 4593, 7898, 4597, 7899, 4601, 7900, 4605, 7901, 4609, 7902, 4613, 7903, 4617, 7904, 4621, 7905, 4625, 7906, 4629, 7907, 4633, 7908, 4637, 7909, 4641, 7910, 4645, 7911, 4649, 7912, 4653, 7913, 4657, 7914, 4661, 7915, 4665, 7916, 4669, 7917, 4673, 7918, 4677, 7919, 4681, 7920, 4685, 7921, 4689, 7922, 4693, 7923, 4697, 7924, 4701, 7925, 4705, 7926, 4709, 7927, 4713, 7928, 4717, 7929, 4721, 7936, 4725, 7937, 4729, 7938, 4733, 7939, 4737, 7940, 4741, 7941, 4745, 7942, 4749, 7943, 4753, 7944, 4757, 7945, 4761, 7946, 4765, 7947, 4769, 7948, 4773, 7949, 4777, 7950, 4781, 7951, 4785, 7952, 4789, 7953, 4793, 7954, 4797, 7955, 4801, 7956, 4805, 7957, 4809, 7960, 4813, 7961, 4817, 7962, 4821, 7963, 4825, 7964, 4829, 7965, 4833, 7968, 4837, 7969, 4841, 7970, 4845, 7971, 4849, 7972, 4853, 7973, 4857, 7974, 4861, 7975, 4865, 7976, 4869, 7977, 4873, 7978, 4877, 7979, 4881, 7980, 4885, 7981, 4889, 7982, 4893, 7983, 4897, 7984, 4901, 7985, 4905, 7986, 4909, 7987, 4913, 7988, 4917, 7989, 4921, 7990, 4925, 7991, 4929, 7992, 4933, 7993, 4937, 7994, 4941, 7995, 4945, 7996, 4949, 7997, 4953, 7998, 4957, 7999, 4961, 8000, 4965, 8001, 4969, 8002, 4973, 8003, 4977, 8004, 4981, 8005, 4985, 8008, 4989, 8009, 4993, 8010, 4997, 8011, 5001, 8012, 5005, 8013, 5009, 8017, 5013, 8019, 5017, 8021, 5021, 8023, 5025, 8025, 5029, 8027, 5033, 8029, 5037, 8031, 5041, 8032, 5045, 8033, 5049, 8034, 5053, 8035, 5057, 8036, 5061, 8037, 5065, 8038, 5069, 8039, 5073, 8040, 5077, 8041, 5081, 8042, 5085, 8043, 5089, 8044, 5093, 8045, 5097, 8046, 5101, 8047, 5105, 8048, 5109, 8049, 5113, 8050, 5117, 8051, 5121, 8052, 5125, 8053, 5129, 8054, 5133, 8055, 5137, 8056, 5141, 8057, 5145, 8058, 5149, 8059, 5153, 8060, 5157, 8061, 5161, 8112, 5165, 8113, 5169, 8120, 5173, 8121, 5177, 8122, 5181, 8123, 5185, 8126, 5189, 8136, 5193, 8137, 5197, 8138, 5201, 8139, 5205, 8144, 5209, 8145, 5213, 8152, 5217, 8153, 5221, 8154, 5225, 8155, 5229, 8160, 5233, 8161, 5237, 8165, 5241, 8168, 5245, 8169, 5249, 8170, 5253, 8171, 5257, 8172, 5261, 8184, 5265, 8185, 5269, 8186, 5273, 8187, 5277, 8498, 5281, 8526, 5285, 8544, 5289, 8545, 5293, 8546, 5297, 8547, 5301, 8548, 5305, 8549, 5309, 8550, 5313, 8551, 5317, 8552, 5321, 8553, 5325, 8554, 5329, 8555, 5333, 8556, 5337, 8557, 5341, 8558, 5345, 8559, 5349, 8560, 5353, 8561, 5357, 8562, 5361, 8563, 5365, 8564, 5369, 8565, 5373, 8566, 5377, 8567, 5381, 8568, 5385, 8569, 5389, 8570, 5393, 8571, 5397, 8572, 5401, 8573, 5405, 8574, 5409, 8575, 5413, 8579, 5417, 8580, 5421, 9398, 5425, 9399, 5429, 9400, 5433, 9401, 5437, 9402, 5441, 9403, 5445, 9404, 5449, 9405, 5453, 9406, 5457, 9407, 5461, 9408, 5465, 9409, 5469, 9410, 5473, 9411, 5477, 9412, 5481, 9413, 5485, 9414, 5489, 9415, 5493, 9416, 5497, 9417, 5501, 9418, 5505, 9419, 5509, 9420, 5513, 9421, 5517, 9422, 5521, 9423, 5525, 9424, 5529, 9425, 5533, 9426, 5537, 9427, 5541, 9428, 5545, 9429, 5549, 9430, 5553, 9431, 5557, 9432, 5561, 9433, 5565, 9434, 5569, 9435, 5573, 9436, 5577, 9437, 5581, 9438, 5585, 9439, 5589, 9440, 5593, 9441, 5597, 9442, 5601, 9443, 5605, 9444, 5609, 9445, 5613, 9446, 5617, 9447, 5621, 9448, 5625, 9449, 5629, 11264, 5633, 11265, 5637, 11266, 5641, 11267, 5645, 11268, 5649, 11269, 5653, 11270, 5657, 11271, 5661, 11272, 5665, 11273, 5669, 11274, 5673, 11275, 5677, 11276, 5681, 11277, 5685, 11278, 5689, 11279, 5693, 11280, 5697, 11281, 5701, 11282, 5705, 11283, 5709, 11284, 5713, 11285, 5717, 11286, 5721, 11287, 5725, 11288, 5729, 11289, 5733, 11290, 5737, 11291, 5741, 11292, 5745, 11293, 5749, 11294, 5753, 11295, 5757, 11296, 5761, 11297, 5765, 11298, 5769, 11299, 5773, 11300, 5777, 11301, 5781, 11302, 5785, 11303, 5789, 11304, 5793, 11305, 5797, 11306, 5801, 11307, 5805, 11308, 5809, 11309, 5813, 11310, 5817, 11312, 5821, 11313, 5825, 11314, 5829, 11315, 5833, 11316, 5837, 11317, 5841, 11318, 5845, 11319, 5849, 11320, 5853, 11321, 5857, 11322, 5861, 11323, 5865, 11324, 5869, 11325, 5873, 11326, 5877, 11327, 5881, 11328, 5885, 11329, 5889, 11330, 5893, 11331, 5897, 11332, 5901, 11333, 5905, 11334, 5909, 11335, 5913, 11336, 5917, 11337, 5921, 11338, 5925, 11339, 5929, 11340, 5933, 11341, 5937, 11342, 5941, 11343, 5945, 11344, 5949, 11345, 5953, 11346, 5957, 11347, 5961, 11348, 5965, 11349, 5969, 11350, 5973, 11351, 5977, 11352, 5981, 11353, 5985, 11354, 5989, 11355, 5993, 11356, 5997, 11357, 6001, 11358, 6005, 11360, 6009, 11361, 6013, 11362, 6017, 11363, 6021, 11364, 6025, 11365, 6029, 11366, 6033, 11367, 6037, 11368, 6041, 11369, 6045, 11370, 6049, 11371, 6053, 11372, 6057, 11381, 6061, 11382, 6065, 11392, 6069, 11393, 6073, 11394, 6077, 11395, 6081, 11396, 6085, 11397, 6089, 11398, 6093, 11399, 6097, 11400, 6101, 11401, 6105, 11402, 6109, 11403, 6113, 11404, 6117, 11405, 6121, 11406, 6125, 11407, 6129, 11408, 6133, 11409, 6137, 11410, 6141, 11411, 6145, 11412, 6149, 11413, 6153, 11414, 6157, 11415, 6161, 11416, 6165, 11417, 6169, 11418, 6173, 11419, 6177, 11420, 6181, 11421, 6185, 11422, 6189, 11423, 6193, 11424, 6197, 11425, 6201, 11426, 6205, 11427, 6209, 11428, 6213, 11429, 6217, 11430, 6221, 11431, 6225, 11432, 6229, 11433, 6233, 11434, 6237, 11435, 6241, 11436, 6245, 11437, 6249, 11438, 6253, 11439, 6257, 11440, 6261, 11441, 6265, 11442, 6269, 11443, 6273, 11444, 6277, 11445, 6281, 11446, 6285, 11447, 6289, 11448, 6293, 11449, 6297, 11450, 6301, 11451, 6305, 11452, 6309, 11453, 6313, 11454, 6317, 11455, 6321, 11456, 6325, 11457, 6329, 11458, 6333, 11459, 6337, 11460, 6341, 11461, 6345, 11462, 6349, 11463, 6353, 11464, 6357, 11465, 6361, 11466, 6365, 11467, 6369, 11468, 6373, 11469, 6377, 11470, 6381, 11471, 6385, 11472, 6389, 11473, 6393, 11474, 6397, 11475, 6401, 11476, 6405, 11477, 6409, 11478, 6413, 11479, 6417, 11480, 6421, 11481, 6425, 11482, 6429, 11483, 6433, 11484, 6437, 11485, 6441, 11486, 6445, 11487, 6449, 11488, 6453, 11489, 6457, 11490, 6461, 11491, 6465, 11520, 6469, 11521, 6473, 11522, 6477, 11523, 6481, 11524, 6485, 11525, 6489, 11526, 6493, 11527, 6497, 11528, 6501, 11529, 6505, 11530, 6509, 11531, 6513, 11532, 6517, 11533, 6521, 11534, 6525, 11535, 6529, 11536, 6533, 11537, 6537, 11538, 6541, 11539, 6545, 11540, 6549, 11541, 6553, 11542, 6557, 11543, 6561, 11544, 6565, 11545, 6569, 11546, 6573, 11547, 6577, 11548, 6581, 11549, 6585, 11550, 6589, 11551, 6593, 11552, 6597, 11553, 6601, 11554, 6605, 11555, 6609, 11556, 6613, 11557, 6617 }; // NOLINT
+static const MultiCharacterSpecialCase<4> kEcma262UnCanonicalizeMultiStrings1[] = { {2, {65313, 65345}}, {2, {65314, 65346}}, {2, {65315, 65347}}, {2, {65316, 65348}}, {2, {65317, 65349}}, {2, {65318, 65350}}, {2, {65319, 65351}}, {2, {65320, 65352}}, {2, {65321, 65353}}, {2, {65322, 65354}}, {2, {65323, 65355}}, {2, {65324, 65356}}, {2, {65325, 65357}}, {2, {65326, 65358}}, {2, {65327, 65359}}, {2, {65328, 65360}}, {2, {65329, 65361}}, {2, {65330, 65362}}, {2, {65331, 65363}}, {2, {65332, 65364}}, {2, {65333, 65365}}, {2, {65334, 65366}}, {2, {65335, 65367}}, {2, {65336, 65368}}, {2, {65337, 65369}}, {2, {65338, 65370}}, {2, {65313, 65345}}, {2, {65314, 65346}}, {2, {65315, 65347}}, {2, {65316, 65348}}, {2, {65317, 65349}}, {2, {65318, 65350}}, {2, {65319, 65351}}, {2, {65320, 65352}}, {2, {65321, 65353}}, {2, {65322, 65354}}, {2, {65323, 65355}}, {2, {65324, 65356}}, {2, {65325, 65357}}, {2, {65326, 65358}}, {2, {65327, 65359}}, {2, {65328, 65360}}, {2, {65329, 65361}}, {2, {65330, 65362}}, {2, {65331, 65363}}, {2, {65332, 65364}}, {2, {65333, 65365}}, {2, {65334, 65366}}, {2, {65335, 65367}}, {2, {65336, 65368}}, {2, {65337, 65369}}, {2, {65338, 65370}}, {0, {0}} }; // NOLINT
+static const uint16_t kEcma262UnCanonicalizeTable1Size = 52;
+static const int32_t kEcma262UnCanonicalizeTable1[104] = { 32545, 1, 32546, 5, 32547, 9, 32548, 13, 32549, 17, 32550, 21, 32551, 25, 32552, 29, 32553, 33, 32554, 37, 32555, 41, 32556, 45, 32557, 49, 32558, 53, 32559, 57, 32560, 61, 32561, 65, 32562, 69, 32563, 73, 32564, 77, 32565, 81, 32566, 85, 32567, 89, 32568, 93, 32569, 97, 32570, 101, 32577, 105, 32578, 109, 32579, 113, 32580, 117, 32581, 121, 32582, 125, 32583, 129, 32584, 133, 32585, 137, 32586, 141, 32587, 145, 32588, 149, 32589, 153, 32590, 157, 32591, 161, 32592, 165, 32593, 169, 32594, 173, 32595, 177, 32596, 181, 32597, 185, 32598, 189, 32599, 193, 32600, 197, 32601, 201, 32602, 205 }; // NOLINT
+static const MultiCharacterSpecialCase<4> kEcma262UnCanonicalizeMultiStrings2[] = { {2, {66560, 66600}}, {2, {66561, 66601}}, {2, {66562, 66602}}, {2, {66563, 66603}}, {2, {66564, 66604}}, {2, {66565, 66605}}, {2, {66566, 66606}}, {2, {66567, 66607}}, {2, {66568, 66608}}, {2, {66569, 66609}}, {2, {66570, 66610}}, {2, {66571, 66611}}, {2, {66572, 66612}}, {2, {66573, 66613}}, {2, {66574, 66614}}, {2, {66575, 66615}}, {2, {66576, 66616}}, {2, {66577, 66617}}, {2, {66578, 66618}}, {2, {66579, 66619}}, {2, {66580, 66620}}, {2, {66581, 66621}}, {2, {66582, 66622}}, {2, {66583, 66623}}, {2, {66584, 66624}}, {2, {66585, 66625}}, {2, {66586, 66626}}, {2, {66587, 66627}}, {2, {66588, 66628}}, {2, {66589, 66629}}, {2, {66590, 66630}}, {2, {66591, 66631}}, {2, {66592, 66632}}, {2, {66593, 66633}}, {2, {66594, 66634}}, {2, {66595, 66635}}, {2, {66596, 66636}}, {2, {66597, 66637}}, {2, {66598, 66638}}, {2, {66599, 66639}}, {2, {66560, 66600}}, {2, {66561, 66601}}, {2, {66562, 66602}}, {2, {66563, 66603}}, {2, {66564, 66604}}, {2, {66565, 66605}}, {2, {66566, 66606}}, {2, {66567, 66607}}, {2, {66568, 66608}}, {2, {66569, 66609}}, {2, {66570, 66610}}, {2, {66571, 66611}}, {2, {66572, 66612}}, {2, {66573, 66613}}, {2, {66574, 66614}}, {2, {66575, 66615}}, {2, {66576, 66616}}, {2, {66577, 66617}}, {2, {66578, 66618}}, {2, {66579, 66619}}, {2, {66580, 66620}}, {2, {66581, 66621}}, {2, {66582, 66622}}, {2, {66583, 66623}}, {2, {66584, 66624}}, {2, {66585, 66625}}, {2, {66586, 66626}}, {2, {66587, 66627}}, {2, {66588, 66628}}, {2, {66589, 66629}}, {2, {66590, 66630}}, {2, {66591, 66631}}, {2, {66592, 66632}}, {2, {66593, 66633}}, {2, {66594, 66634}}, {2, {66595, 66635}}, {2, {66596, 66636}}, {2, {66597, 66637}}, {2, {66598, 66638}}, {2, {66599, 66639}}, {0, {0}} }; // NOLINT
+static const uint16_t kEcma262UnCanonicalizeTable2Size = 80;
+static const int32_t kEcma262UnCanonicalizeTable2[160] = { 1024, 1, 1025, 5, 1026, 9, 1027, 13, 1028, 17, 1029, 21, 1030, 25, 1031, 29, 1032, 33, 1033, 37, 1034, 41, 1035, 45, 1036, 49, 1037, 53, 1038, 57, 1039, 61, 1040, 65, 1041, 69, 1042, 73, 1043, 77, 1044, 81, 1045, 85, 1046, 89, 1047, 93, 1048, 97, 1049, 101, 1050, 105, 1051, 109, 1052, 113, 1053, 117, 1054, 121, 1055, 125, 1056, 129, 1057, 133, 1058, 137, 1059, 141, 1060, 145, 1061, 149, 1062, 153, 1063, 157, 1064, 161, 1065, 165, 1066, 169, 1067, 173, 1068, 177, 1069, 181, 1070, 185, 1071, 189, 1072, 193, 1073, 197, 1074, 201, 1075, 205, 1076, 209, 1077, 213, 1078, 217, 1079, 221, 1080, 225, 1081, 229, 1082, 233, 1083, 237, 1084, 241, 1085, 245, 1086, 249, 1087, 253, 1088, 257, 1089, 261, 1090, 265, 1091, 269, 1092, 273, 1093, 277, 1094, 281, 1095, 285, 1096, 289, 1097, 293, 1098, 297, 1099, 301, 1100, 305, 1101, 309, 1102, 313, 1103, 317 }; // NOLINT
+int Ecma262UnCanonicalize::Convert(uchar c,
+                      uchar n,
+                      uchar* result,
+                      bool* allow_caching_ptr) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupMapping(kEcma262UnCanonicalizeTable0,
+                                     kEcma262UnCanonicalizeTable0Size,
+                                     kEcma262UnCanonicalizeMultiStrings0,
+                                     c,
+                                     n,
+                                     result,
+                                     allow_caching_ptr);
+    case 1: return LookupMapping(kEcma262UnCanonicalizeTable1,
+                                     kEcma262UnCanonicalizeTable1Size,
+                                     kEcma262UnCanonicalizeMultiStrings1,
+                                     c,
+                                     n,
+                                     result,
+                                     allow_caching_ptr);
+    case 2: return LookupMapping(kEcma262UnCanonicalizeTable2,
+                                     kEcma262UnCanonicalizeTable2Size,
+                                     kEcma262UnCanonicalizeMultiStrings2,
+                                     c,
+                                     n,
+                                     result,
+                                     allow_caching_ptr);
+    default: return 0;
+  }
+}
+
+static const MultiCharacterSpecialCase<1> kCanonicalizationRangeMultiStrings0[] = { {0, {0}} }; // NOLINT
+static const uint16_t kCanonicalizationRangeTable0Size = 1838;
+static const int32_t kCanonicalizationRangeTable0[3676] = { 0, 67109124, 1073741825, 0, 64, 0, 65, 67108708, 1073741890, -260, 90, -260, 91, 67108524, 1073741916, -364, 96, -364, 97, 67108580, 1073741922, -388, 122, -388, 123, 67108604, 1073741948, -492, 180, -492, 181, 67108144, 182, 67108176, 1073742007, -728, 191, -728, 192, 67108188, 1073742017, -768, 214, -768, 215, 67108008, 216, 67108028, 1073742041, -864, 222, -864, 223, 67107976, 224, 67108060, 1073742049, -896, 246, -896, 247, 67107880, 248, 67107900, 1073742073, -992, 254, -992, 255, 67107848, 256, 67107844, 257, 67107840, 258, 67107836, 259, 67107832, 260, 67107828, 261, 67107824, 262, 67107820, 263, 67107816, 264, 67107812, 265, 67107808, 266, 67107804, 267, 67107800, 268, 67107796, 269, 67107792, 270, 67107788, 271, 67107784, 272, 67107780, 273, 67107776, 274, 67107772, 275, 67107768, 276, 67107764, 277, 67107760, 278, 67107756, 279, 67107752, 280, 67107748, 281, 67107744, 282, 67107740, 283, 67107736, 284, 67107732, 285, 67107728, 286, 67107724, 287, 67107720, 288, 67107716, 289, 67107712, 290, 67107708, 291, 67107704, 292, 67107700, 293, 67107696, 294, 67107692, 295, 67107688, 296, 67107684, 297, 67107680, 298, 67107676, 299, 67107672, 300, 67107668, 301, 67107664, 302, 67107660, 1073742127, 67107656, 304, 67107656, 305, -1216, 306, 67107644, 307, 67107640, 308, 67107636, 309, 67107632, 310, 67107628, 311, 67107624, 312, 67107620, 313, 67107616, 314, 67107612, 315, 67107608, 316, 67107604, 317, 67107600, 318, 67107596, 319, 67107592, 320, 67107588, 321, 67107584, 322, 67107580, 323, 67107576, 324, 67107572, 325, 67107568, 326, 67107564, 327, 67107560, 328, 67107556, 329, 67107552, 330, 67107548, 331, 67107544, 332, 67107540, 333, 67107536, 334, 67107532, 335, 67107528, 336, 67107524, 337, 67107520, 338, 67107516, 339, 67107512, 340, 67107508, 341, 67107504, 342, 67107500, 343, 67107496, 344, 67107492, 345, 67107488, 346, 67107484, 347, 67107480, 348, 67107476, 349, 67107472, 350, 67107468, 351, 67107464, 352, 67107460, 353, 67107456, 354, 67107452, 355, 67107448, 356, 67107444, 357, 67107440, 358, 67107436, 359, 67107432, 360, 67107428, 361, 67107424, 362, 67107420, 363, 67107416, 364, 67107412, 365, 67107408, 366, 67107404, 367, 67107400, 368, 67107396, 369, 67107392, 370, 67107388, 371, 67107384, 372, 67107380, 373, 67107376, 374, 67107372, 375, 67107368, 376, 67107364, 377, 67107360, 378, 67107356, 379, 67107352, 380, 67107348, 381, 67107344, 382, 67107340, 383, 67107336, 384, 67107332, 385, 67107328, 386, 67107324, 387, 67107320, 388, 67107316, 389, 67107312, 390, 67107308, 391, 67107304, 1073742216, 67107300, 393, 67107300, 394, -1572, 395, 67107288, 396, 67107284, 397, 67107280, 398, 67107276, 399, 67107272, 400, 67107268, 401, 67107264, 402, 67107260, 403, 67107256, 404, 67107252, 405, 67107248, 406, 67107244, 407, 67107240, 408, 67107236, 409, 67107232, 410, 67107228, 411, 67107224, 412, 67107220, 413, 67107216, 414, 67107212, 415, 67107208, 416, 67107204, 417, 67107200, 418, 67107196, 419, 67107192, 420, 67107188, 421, 67107184, 422, 67107180, 423, 67107176, 424, 67107172, 1073742249, 67107168, 426, 67107168, 427, -1704, 428, 67107156, 429, 67107152, 430, 67107148, 431, 67107144, 1073742256, 67107140, 433, 67107140, 434, -1732, 435, 67107128, 436, 67107124, 437, 67107120, 438, 67107116, 439, 67107112, 440, 67107108, 1073742265, 67107104, 442, 67107104, 443, -1768, 444, 67107092, 445, 67107088, 446, 67107084, 447, 67107080, 448, 67107088, 1073742273, -1792, 451, -1792, 452, 67107060, 453, 67107056, 454, 67107052, 455, 67107048, 456, 67107044, 457, 67107040, 458, 67107036, 459, 67107032, 460, 67107028, 461, 67107024, 462, 67107020, 463, 67107016, 464, 67107012, 465, 67107008, 466, 67107004, 467, 67107000, 468, 67106996, 469, 67106992, 470, 67106988, 471, 67106984, 472, 67106980, 473, 67106976, 474, 67106972, 475, 67106968, 476, 67106964, 477, 67106960, 478, 67106956, 479, 67106952, 480, 67106948, 481, 67106944, 482, 67106940, 483, 67106936, 484, 67106932, 485, 67106928, 486, 67106924, 487, 67106920, 488, 67106916, 489, 67106912, 490, 67106908, 491, 67106904, 492, 67106900, 493, 67106896, 494, 67106892, 495, 67106888, 496, 67106884, 497, 67106880, 498, 67106876, 499, 67106872, 500, 67106868, 501, 67106864, 502, 67106860, 503, 67106856, 504, 67106852, 505, 67106848, 506, 67106844, 507, 67106840, 508, 67106836, 509, 67106832, 510, 67106828, 511, 67106824, 512, 67106820, 513, 67106816, 514, 67106812, 515, 67106808, 516, 67106804, 517, 67106800, 518, 67106796, 519, 67106792, 520, 67106788, 521, 67106784, 522, 67106780, 523, 67106776, 524, 67106772, 525, 67106768, 526, 67106764, 527, 67106760, 528, 67106756, 529, 67106752, 530, 67106748, 531, 67106744, 532, 67106740, 533, 67106736, 534, 67106732, 535, 67106728, 536, 67106724, 537, 67106720, 538, 67106716, 539, 67106712, 540, 67106708, 541, 67106704, 542, 67106700, 543, 67106696, 544, 67106692, 545, 67106688, 546, 67106684, 547, 67106680, 548, 67106676, 549, 67106672, 550, 67106668, 551, 67106664, 552, 67106660, 553, 67106656, 554, 67106652, 555, 67106648, 556, 67106644, 557, 67106640, 558, 67106636, 559, 67106632, 560, 67106628, 561, 67106624, 562, 67106620, 563, 67106616, 564, 67106636, 1073742389, -2256, 570, -2256, 571, 67106584, 572, 67106580, 573, 67106576, 574, 67106580, 1073742399, -2296, 576, -2296, 577, 67106560, 578, 67106556, 579, 67106552, 580, 67106548, 581, 67106544, 582, 67106540, 583, 67106536, 584, 67106532, 585, 67106528, 586, 67106524, 587, 67106520, 588, 67106516, 589, 67106512, 590, 67106508, 591, 67106504, 592, 67106508, 1073742417, -2368, 594, -2368, 595, 67106488, 596, 67106484, 1073742421, 67106480, 598, 67106480, 599, -2392, 600, 67106468, 601, 67106464, 602, 67106460, 603, 67106456, 604, 67106464, 1073742429, -2416, 607, -2416, 1073742432, 67106436, 609, 67106436, 610, -2436, 611, 67106424, 612, 67106432, 1073742437, -2448, 615, -2448, 616, 67106404, 617, 67106400, 618, 67106396, 619, 67106392, 620, 67106396, 1073742445, -2480, 622, -2480, 1073742447, 67106376, 624, 67106376, 625, -2496, 1073742450, 67106364, 627, 67106364, 628, -2508, 629, 67106352, 630, 67106372, 1073742455, -2520, 636, -2520, 1073742461, 67106320, 638, 67106320, 639, -2552, 1073742464, 67106308, 641, 67106308, 642, -2564, 643, 67106296, 644, 67106304, 1073742469, -2576, 647, -2576, 648, 67106276, 1073742473, 67106272, 650, 67106272, 651, -2600, 652, 67106260, 653, 67106272, 1073742478, -2612, 657, -2612, 658, 67106236, 659, 67106940, 1073742484, -2636, 836, -2636, 837, 67105520, 838, 67105724, 1073742663, -3352, 879, -3352, 1073742708, -3352, 885, -3352, 890, -3352, 891, 67105312, 1073742716, -3564, 893, -3564, 894, 67105320, 1073742724, -3576, 901, -3576, 902, 67105260, 903, 67105256, 904, 67105260, 1073742729, -3616, 906, -3616, 908, 67105236, 910, 67105232, 911, -3640, 912, 67105220, 913, 67105216, 1073742738, 67105212, 915, 67105212, 916, -3660, 1073742741, 67105200, 918, 67105200, 919, -3672, 920, 67105188, 921, 67105184, 922, 67105180, 923, 67105176, 924, 67105172, 925, 67105176, 1073742750, -3700, 927, -3700, 928, 67105156, 929, 67105152, 1073742755, 6, 932, 67105144, 933, -3728, 934, 67105132, 935, 67105144, 1073742760, -3740, 939, -3740, 940, 67105108, 941, 67105112, 1073742766, -3764, 943, -3764, 944, 67105092, 945, 67105088, 1073742770, 67105084, 947, 67105084, 948, -3788, 1073742773, 67105072, 950, 67105072, 951, -3800, 952, 67105060, 953, 67105056, 954, 67105052, 955, 67105048, 956, 67105044, 957, 67105048, 1073742782, -3828, 959, -3828, 960, 67105028, 961, 67105024, 962, 67105020, 1073742787, 67105016, 964, 67105016, 965, -3856, 966, 67105004, 967, 67105016, 1073742792, -3868, 971, -3868, 1073742796, 67104980, 973, 67104980, 974, -3892, 976, 67104964, 977, 67104960, 978, 67104964, 1073742803, -3912, 980, -3912, 981, 67104944, 982, 67104940, 983, 67104936, 984, 67104932, 985, 67104928, 986, 67104924, 987, 67104920, 988, 67104916, 989, 67104912, 990, 67104908, 991, 67104904, 992, 67104900, 993, 67104896, 994, 67104892, 995, 67104888, 996, 67104884, 997, 67104880, 998, 67104876, 999, 67104872, 1000, 67104868, 1001, 67104864, 1002, 67104860, 1003, 67104856, 1004, 67104852, 1005, 67104848, 1006, 67104844, 1007, 67104840, 1008, 67104836, 1009, 67104832, 1073742834, 67104828, 1011, 67104828, 1012, -4044, 1013, 67104816, 1014, 67104812, 1015, 67104808, 1016, 67104804, 1017, 67104800, 1018, 67104796, 1019, 67104792, 1020, 67104788, 1021, 67104792, 1073742846, -4084, 1023, -4084, 1024, 67104832, 1073742849, -4096, 1039, -4096, 1040, 67104832, 1073742865, -4160, 1071, -4160, 1072, 67104704, 1073742897, -4288, 1103, -4288, 1104, 67104512, 1073742929, -4416, 1119, -4416, 1120, 67104388, 1121, 67104384, 1122, 67104380, 1123, 67104376, 1124, 67104372, 1125, 67104368, 1126, 67104364, 1127, 67104360, 1128, 67104356, 1129, 67104352, 1130, 67104348, 1131, 67104344, 1132, 67104340, 1133, 67104336, 1134, 67104332, 1135, 67104328, 1136, 67104324, 1137, 67104320, 1138, 67104316, 1139, 67104312, 1140, 67104308, 1141, 67104304, 1142, 67104300, 1143, 67104296, 1144, 67104292, 1145, 67104288, 1146, 67104284, 1147, 67104280, 1148, 67104276, 1149, 67104272, 1150, 67104268, 1151, 67104264, 1152, 67104260, 1153, 67104256, 1154, 67104280, 1073742979, -4616, 1158, -4616, 1073742984, -4616, 1161, -4616, 1162, 67104220, 1163, 67104216, 1164, 67104212, 1165, 67104208, 1166, 67104204, 1167, 67104200, 1168, 67104196, 1169, 67104192, 1170, 67104188, 1171, 67104184, 1172, 67104180, 1173, 67104176, 1174, 67104172, 1175, 67104168, 1176, 67104164, 1177, 67104160, 1178, 67104156, 1179, 67104152, 1180, 67104148, 1181, 67104144, 1182, 67104140, 1183, 67104136, 1184, 67104132, 1185, 67104128, 1186, 67104124, 1187, 67104120, 1188, 67104116, 1189, 67104112, 1190, 67104108, 1191, 67104104, 1192, 67104100, 1193, 67104096, 1194, 67104092, 1195, 67104088, 1196, 67104084, 1197, 67104080, 1198, 67104076, 1199, 67104072, 1200, 67104068, 1201, 67104064, 1202, 67104060, 1203, 67104056, 1204, 67104052, 1205, 67104048, 1206, 67104044, 1207, 67104040, 1208, 67104036, 1209, 67104032, 1210, 67104028, 1211, 67104024, 1212, 67104020, 1213, 67104016, 1214, 67104012, 1215, 67104008, 1216, 67104004, 1217, 67104000, 1218, 67103996, 1219, 67103992, 1220, 67103988, 1221, 67103984, 1222, 67103980, 1223, 67103976, 1224, 67103972, 1225, 67103968, 1226, 67103964, 1227, 67103960, 1228, 67103956, 1229, 67103952, 1230, 67103948, 1231, 67103944, 1232, 67103940, 1233, 67103936, 1234, 67103932, 1235, 67103928, 1236, 67103924, 1237, 67103920, 1238, 67103916, 1239, 67103912, 1240, 67103908, 1241, 67103904, 1242, 67103900, 1243, 67103896, 1244, 67103892, 1245, 67103888, 1246, 67103884, 1247, 67103880, 1248, 67103876, 1249, 67103872, 1250, 67103868, 1251, 67103864, 1252, 67103860, 1253, 67103856, 1254, 67103852, 1255, 67103848, 1256, 67103844, 1257, 67103840, 1258, 67103836, 1259, 67103832, 1260, 67103828, 1261, 67103824, 1262, 67103820, 1263, 67103816, 1264, 67103812, 1265, 67103808, 1266, 67103804, 1267, 67103800, 1268, 67103796, 1269, 67103792, 1270, 67103788, 1271, 67103784, 1272, 67103780, 1273, 67103776, 1274, 67103772, 1275, 67103768, 1276, 67103764, 1277, 67103760, 1278, 67103756, 1279, 67103752, 1280, 67103748, 1281, 67103744, 1282, 67103740, 1283, 67103736, 1284, 67103732, 1285, 67103728, 1286, 67103724, 1287, 67103720, 1288, 67103716, 1289, 67103712, 1290, 67103708, 1291, 67103704, 1292, 67103700, 1293, 67103696, 1294, 67103692, 1295, 67103688, 1296, 67103684, 1297, 67103680, 1298, 67103676, 1299, 67103672, 1329, 67103700, 1073743154, -5316, 1366, -5316, 1073743193, -5468, 1375, -5468, 1377, 67103508, 1073743202, -5508, 1414, -5508, 1415, 67114568, 1073743241, -5660, 1418, -5660, 1073743249, -5660, 1479, -5660, 1073743312, -5660, 1514, -5660, 1073743344, -5660, 1524, -5660, 1073743360, -5660, 1539, -5660, 1073743371, -5660, 1557, -5660, 1563, -5660, 1073743390, -5660, 1567, -5660, 1073743393, -5660, 1594, -5660, 1073743424, -5660, 1630, -5660, 1073743456, -5660, 1805, -5660, 1073743631, -5660, 1866, -5660, 1073743693, -5660, 1901, -5660, 1073743744, -5660, 1969, -5660, 1073743808, -5660, 2042, -5660, 1073744129, -5660, 2361, -5660, 1073744188, -5660, 2381, -5660, 1073744208, -5660, 2388, -5660, 1073744216, -5660, 2416, -5660, 1073744251, -5660, 2431, -5660, 1073744257, -5660, 2435, -5660, 1073744261, -5660, 2444, -5660, 1073744271, -5660, 2448, -5660, 1073744275, -5660, 2472, -5660, 1073744298, -5660, 2480, -5660, 2482, -5660, 1073744310, -5660, 2489, -5660, 1073744316, -5660, 2500, -5660, 1073744327, -5660, 2504, -5660, 1073744331, -5660, 2510, -5660, 2519, -5660, 1073744348, -5660, 2525, -5660, 1073744351, -5660, 2531, -5660, 1073744358, -5660, 2554, -5660, 1073744385, -5660, 2563, -5660, 1073744389, -5660, 2570, -5660, 1073744399, -5660, 2576, -5660, 1073744403, -5660, 2600, -5660, 1073744426, -5660, 2608, -5660, 1073744434, -5660, 2611, -5660, 1073744437, -5660, 2614, -5660, 1073744440, -5660, 2617, -5660, 2620, -5660, 1073744446, -5660, 2626, -5660, 1073744455, -5660, 2632, -5660, 1073744459, -5660, 2637, -5660, 1073744473, -5660, 2652, -5660, 2654, -5660, 1073744486, -5660, 2676, -5660, 1073744513, -5660, 2691, -5660, 1073744517, -5660, 2701, -5660, 1073744527, -5660, 2705, -5660, 1073744531, -5660, 2728, -5660, 1073744554, -5660, 2736, -5660, 1073744562, -5660, 2739, -5660, 1073744565, -5660, 2745, -5660, 1073744572, -5660, 2757, -5660, 1073744583, -5660, 2761, -5660, 1073744587, -5660, 2765, -5660, 2768, -5660, 1073744608, -5660, 2787, -5660, 1073744614, -5660, 2799, -5660, 2801, -5660, 1073744641, -5660, 2819, -5660, 1073744645, -5660, 2828, -5660, 1073744655, -5660, 2832, -5660, 1073744659, -5660, 2856, -5660, 1073744682, -5660, 2864, -5660, 1073744690, -5660, 2867, -5660, 1073744693, -5660, 2873, -5660, 1073744700, -5660, 2883, -5660, 1073744711, -5660, 2888, -5660, 1073744715, -5660, 2893, -5660, 1073744726, -5660, 2903, -5660, 1073744732, -5660, 2909, -5660, 1073744735, -5660, 2913, -5660, 1073744742, -5660, 2929, -5660, 1073744770, -5660, 2947, -5660, 1073744773, -5660, 2954, -5660, 1073744782, -5660, 2960, -5660, 1073744786, -5660, 2965, -5660, 1073744793, -5660, 2970, -5660, 2972, -5660, 1073744798, -5660, 2975, -5660, 1073744803, -5660, 2980, -5660, 1073744808, -5660, 2986, -5660, 1073744814, -5660, 3001, -5660, 1073744830, -5660, 3010, -5660, 1073744838, -5660, 3016, -5660, 1073744842, -5660, 3021, -5660, 3031, -5660, 1073744870, -5660, 3066, -5660, 1073744897, -5660, 3075, -5660, 1073744901, -5660, 3084, -5660, 1073744910, -5660, 3088, -5660, 1073744914, -5660, 3112, -5660, 1073744938, -5660, 3123, -5660, 1073744949, -5660, 3129, -5660, 1073744958, -5660, 3140, -5660, 1073744966, -5660, 3144, -5660, 1073744970, -5660, 3149, -5660, 1073744981, -5660, 3158, -5660, 1073744992, -5660, 3169, -5660, 1073744998, -5660, 3183, -5660, 1073745026, -5660, 3203, -5660, 1073745029, -5660, 3212, -5660, 1073745038, -5660, 3216, -5660, 1073745042, -5660, 3240, -5660, 1073745066, -5660, 3251, -5660, 1073745077, -5660, 3257, -5660, 1073745084, -5660, 3268, -5660, 1073745094, -5660, 3272, -5660, 1073745098, -5660, 3277, -5660, 1073745109, -5660, 3286, -5660, 3294, -5660, 1073745120, -5660, 3299, -5660, 1073745126, -5660, 3311, -5660, 1073745137, -5660, 3314, -5660, 1073745154, -5660, 3331, -5660, 1073745157, -5660, 3340, -5660, 1073745166, -5660, 3344, -5660, 1073745170, -5660, 3368, -5660, 1073745194, -5660, 3385, -5660, 1073745214, -5660, 3395, -5660, 1073745222, -5660, 3400, -5660, 1073745226, -5660, 3405, -5660, 3415, -5660, 1073745248, -5660, 3425, -5660, 1073745254, -5660, 3439, -5660, 1073745282, -5660, 3459, -5660, 1073745285, -5660, 3478, -5660, 1073745306, -5660, 3505, -5660, 1073745331, -5660, 3515, -5660, 3517, -5660, 1073745344, -5660, 3526, -5660, 3530, -5660, 1073745359, -5660, 3540, -5660, 3542, -5660, 1073745368, -5660, 3551, -5660, 1073745394, -5660, 3572, -5660, 1073745409, -5660, 3642, -5660, 1073745471, -5660, 3675, -5660, 1073745537, -5660, 3714, -5660, 3716, -5660, 1073745543, -5660, 3720, -5660, 3722, -5660, 3725, -5660, 1073745556, -5660, 3735, -5660, 1073745561, -5660, 3743, -5660, 1073745569, -5660, 3747, -5660, 3749, -5660, 3751, -5660, 1073745578, -5660, 3755, -5660, 1073745581, -5660, 3769, -5660, 1073745595, -5660, 3773, -5660, 1073745600, -5660, 3780, -5660, 3782, -5660, 1073745608, -5660, 3789, -5660, 1073745616, -5660, 3801, -5660, 1073745628, -5660, 3805, -5660, 1073745664, -5660, 3911, -5660, 1073745737, -5660, 3946, -5660, 1073745777, -5660, 3979, -5660, 1073745808, -5660, 3991, -5660, 1073745817, -5660, 4028, -5660, 1073745854, -5660, 4044, -5660, 1073745871, -5660, 4049, -5660, 1073745920, -5660, 4129, -5660, 1073745955, -5660, 4135, -5660, 1073745961, -5660, 4138, -5660, 1073745964, -5660, 4146, -5660, 1073745974, -5660, 4153, -5660, 1073745984, -5660, 4185, -5660, 4256, 67091992, 1073746081, -17024, 4293, -17024, 1073746128, -17176, 4348, -17176, 1073746176, -17176, 4441, -17176, 1073746271, -17176, 4514, -17176, 1073746344, -17176, 4601, -17176, 1073746432, -17176, 4680, -17176, 1073746506, -17176, 4685, -17176, 1073746512, -17176, 4694, -17176, 4696, -17176, 1073746522, -17176, 4701, -17176, 1073746528, -17176, 4744, -17176, 1073746570, -17176, 4749, -17176, 1073746576, -17176, 4784, -17176, 1073746610, -17176, 4789, -17176, 1073746616, -17176, 4798, -17176, 4800, -17176, 1073746626, -17176, 4805, -17176, 1073746632, -17176, 4822, -17176, 1073746648, -17176, 4880, -17176, 1073746706, -17176, 4885, -17176, 1073746712, -17176, 4954, -17176, 1073746783, -17176, 4988, -17176, 1073746816, -17176, 5017, -17176, 1073746848, -17176, 5108, -17176, 1073746945, -17176, 5750, -17176, 1073747584, -17176, 5788, -17176, 1073747616, -17176, 5872, -17176, 1073747712, -17176, 5900, -17176, 1073747726, -17176, 5908, -17176, 1073747744, -17176, 5942, -17176, 1073747776, -17176, 5971, -17176, 1073747808, -17176, 5996, -17176, 1073747822, -17176, 6000, -17176, 1073747826, -17176, 6003, -17176, 1073747840, -17176, 6109, -17176, 1073747936, -17176, 6121, -17176, 1073747952, -17176, 6137, -17176, 1073747968, -17176, 6158, -17176, 1073747984, -17176, 6169, -17176, 1073748000, -17176, 6263, -17176, 1073748096, -17176, 6313, -17176, 1073748224, -17176, 6428, -17176, 1073748256, -17176, 6443, -17176, 1073748272, -17176, 6459, -17176, 6464, -17176, 1073748292, -17176, 6509, -17176, 1073748336, -17176, 6516, -17176, 1073748352, -17176, 6569, -17176, 1073748400, -17176, 6601, -17176, 1073748432, -17176, 6617, -17176, 1073748446, -17176, 6683, -17176, 1073748510, -17176, 6687, -17176, 1073748736, -17176, 6987, -17176, 1073748816, -17176, 7036, -17176, 1073749248, -17176, 7548, -17176, 7549, 67078672, 7550, 67079184, 1073749375, -30200, 7626, -30200, 1073749502, -30200, 7679, -30200, 7680, 67078148, 7681, 67078144, 7682, 67078140, 7683, 67078136, 7684, 67078132, 7685, 67078128, 7686, 67078124, 7687, 67078120, 7688, 67078116, 7689, 67078112, 7690, 67078108, 7691, 67078104, 7692, 67078100, 7693, 67078096, 7694, 67078092, 7695, 67078088, 7696, 67078084, 7697, 67078080, 7698, 67078076, 7699, 67078072, 7700, 67078068, 7701, 67078064, 7702, 67078060, 7703, 67078056, 7704, 67078052, 7705, 67078048, 7706, 67078044, 7707, 67078040, 7708, 67078036, 7709, 67078032, 7710, 67078028, 7711, 67078024, 7712, 67078020, 7713, 67078016, 7714, 67078012, 7715, 67078008, 7716, 67078004, 7717, 67078000, 7718, 67077996, 7719, 67077992, 7720, 67077988, 7721, 67077984, 7722, 67077980, 7723, 67077976, 7724, 67077972, 7725, 67077968, 7726, 67077964, 7727, 67077960, 7728, 67077956, 7729, 67077952, 7730, 67077948, 7731, 67077944, 7732, 67077940, 7733, 67077936, 7734, 67077932, 7735, 67077928, 7736, 67077924, 7737, 67077920, 7738, 67077916, 7739, 67077912, 7740, 67077908, 7741, 67077904, 7742, 67077900, 7743, 67077896, 7744, 67077892, 7745, 67077888, 7746, 67077884, 7747, 67077880, 7748, 67077876, 7749, 67077872, 7750, 67077868, 7751, 67077864, 7752, 67077860, 7753, 67077856, 7754, 67077852, 7755, 67077848, 7756, 67077844, 7757, 67077840, 7758, 67077836, 7759, 67077832, 7760, 67077828, 7761, 67077824, 7762, 67077820, 7763, 67077816, 7764, 67077812, 7765, 67077808, 7766, 67077804, 7767, 67077800, 7768, 67077796, 7769, 67077792, 7770, 67077788, 7771, 67077784, 7772, 67077780, 7773, 67077776, 7774, 67077772, 7775, 67077768, 7776, 67077764, 7777, 67077760, 7778, 67077756, 7779, 67077752, 7780, 67077748, 7781, 67077744, 7782, 67077740, 7783, 67077736, 7784, 67077732, 7785, 67077728, 7786, 67077724, 7787, 67077720, 7788, 67077716, 7789, 67077712, 7790, 67077708, 7791, 67077704, 7792, 67077700, 7793, 67077696, 7794, 67077692, 7795, 67077688, 7796, 67077684, 7797, 67077680, 7798, 67077676, 7799, 67077672, 7800, 67077668, 7801, 67077664, 7802, 67077660, 7803, 67077656, 7804, 67077652, 7805, 67077648, 7806, 67077644, 7807, 67077640, 7808, 67077636, 7809, 67077632, 7810, 67077628, 7811, 67077624, 7812, 67077620, 7813, 67077616, 7814, 67077612, 7815, 67077608, 7816, 67077604, 7817, 67077600, 7818, 67077596, 7819, 67077592, 7820, 67077588, 7821, 67077584, 7822, 67077580, 7823, 67077576, 7824, 67077572, 7825, 67077568, 7826, 67077564, 7827, 67077560, 7828, 67077556, 7829, 67077552, 7830, 67077564, 1073749655, -31320, 7834, -31320, 7835, 67077528, 7840, 67077508, 7841, 67077504, 7842, 67077500, 7843, 67077496, 7844, 67077492, 7845, 67077488, 7846, 67077484, 7847, 67077480, 7848, 67077476, 7849, 67077472, 7850, 67077468, 7851, 67077464, 7852, 67077460, 7853, 67077456, 7854, 67077452, 7855, 67077448, 7856, 67077444, 7857, 67077440, 7858, 67077436, 7859, 67077432, 7860, 67077428, 7861, 67077424, 7862, 67077420, 7863, 67077416, 7864, 67077412, 7865, 67077408, 7866, 67077404, 7867, 67077400, 7868, 67077396, 7869, 67077392, 7870, 67077388, 7871, 67077384, 7872, 67077380, 7873, 67077376, 7874, 67077372, 7875, 67077368, 7876, 67077364, 7877, 67077360, 7878, 67077356, 7879, 67077352, 7880, 67077348, 7881, 67077344, 7882, 67077340, 7883, 67077336, 7884, 67077332, 7885, 67077328, 7886, 67077324, 7887, 67077320, 7888, 67077316, 7889, 67077312, 7890, 67077308, 7891, 67077304, 7892, 67077300, 7893, 67077296, 7894, 67077292, 7895, 67077288, 7896, 67077284, 7897, 67077280, 7898, 67077276, 7899, 67077272, 7900, 67077268, 7901, 67077264, 7902, 67077260, 7903, 67077256, 7904, 67077252, 7905, 67077248, 7906, 67077244, 7907, 67077240, 7908, 67077236, 7909, 67077232, 7910, 67077228, 7911, 67077224, 7912, 67077220, 7913, 67077216, 7914, 67077212, 7915, 67077208, 7916, 67077204, 7917, 67077200, 7918, 67077196, 7919, 67077192, 7920, 67077188, 7921, 67077184, 7922, 67077180, 7923, 67077176, 7924, 67077172, 7925, 67077168, 7926, 67077164, 7927, 67077160, 7928, 67077156, 7929, 67077152, 7936, 67077152, 1073749761, -31744, 7943, -31744, 7944, 67077120, 1073749769, -31776, 7951, -31776, 7952, 67077080, 1073749777, -31808, 7957, -31808, 7960, 67077048, 1073749785, -31840, 7965, -31840, 7968, 67077024, 1073749793, -31872, 7975, -31872, 7976, 67076992, 1073749801, -31904, 7983, -31904, 7984, 67076960, 1073749809, -31936, 7991, -31936, 7992, 67076928, 1073749817, -31968, 7999, -31968, 8000, 67076888, 1073749825, -32000, 8005, -32000, 8008, 67076856, 1073749833, -32032, 8013, -32032, 8016, -32056, 8017, 67076800, 8018, 67076796, 8019, 67076792, 8020, 67076788, 8021, 67076784, 8022, 67076780, 8023, 67076776, 8025, 67076768, 8027, 67076760, 8029, 67076752, 8031, 67076744, 8032, 67076768, 1073749857, -32128, 8039, -32128, 8040, 67076736, 1073749865, -32160, 8047, -32160, 8048, 67076680, 8049, -32192, 8050, 67076680, 1073749875, -32200, 8053, -32200, 8054, 67076656, 8055, -32216, 8056, 67076648, 8057, -32224, 8058, 67076640, 8059, -32232, 8060, 67076632, 8061, -32240, 1073749888, -32248, 8111, -32248, 8112, 67076424, 8113, -32448, 8114, 67076432, 1073749939, -32456, 8116, -32456, 1073749942, -32456, 8119, -32456, 8120, 67076392, 8121, -32480, 8122, 67076384, 8123, -32488, 8124, 67076376, 8125, -32496, 8126, 67076364, 8127, 67076392, 1073749952, -32508, 8132, -32508, 1073749958, -32508, 8135, -32508, 8136, 67076336, 1073749961, -32544, 8139, -32544, 8140, 67076320, 1073749965, -32560, 8143, -32560, 8144, 67076296, 8145, -32576, 8146, 67076304, 8147, -32584, 1073749974, -32584, 8151, -32584, 8152, 67076264, 8153, -32608, 8154, 67076256, 8155, -32616, 1073749981, -32624, 8159, -32624, 8160, 67076232, 8161, -32640, 8162, 67076228, 1073749987, -32648, 8164, -32648, 1073749989, 67076208, 8166, 67076208, 8167, -32664, 8168, 67076200, 8169, -32672, 8170, 67076192, 8171, -32680, 8172, 67076180, 8173, 67076216, 1073749998, -32692, 8175, -32692, 1073750002, -32692, 8180, -32692, 1073750006, -32692, 8183, -32692, 8184, 67076136, 8185, -32736, 8186, 67076128, 8187, -32744, 8188, 67077352, 1073750013, -32752, 8190, -32752, 1073750016, -32752, 8291, -32752, 1073750122, -32752, 8305, -32752, 1073750132, -32752, 8334, -32752, 1073750160, -32752, 8340, -32752, 1073750176, -32752, 8373, -32752, 1073750224, -32752, 8431, -32752, 1073750272, -32752, 8497, -32752, 8498, 67074876, 8499, 67074976, 1073750324, -33996, 8525, -33996, 8526, 67074764, 1073750355, -34108, 8543, -34108, 8544, 67074752, 1073750369, -34176, 8559, -34176, 8560, 67074688, 1073750385, -34240, 8575, -34240, 8576, 67074572, 1073750401, -34304, 8578, -34304, 8579, 67074552, 8580, 67074548, 1073750416, -34324, 9191, -34324, 1073751040, -34324, 9254, -34324, 1073751104, -34324, 9290, -34324, 1073751136, -34324, 9397, -34324, 9398, 67071376, 1073751223, -37592, 9423, -37592, 9424, 67071272, 1073751249, -37696, 9449, -37696, 9450, 67078320, 1073751275, -37800, 9884, -37800, 1073751712, -37800, 9906, -37800, 1073751809, -37800, 9988, -37800, 1073751814, -37800, 9993, -37800, 1073751820, -37800, 10023, -37800, 1073751849, -37800, 10059, -37800, 10061, -37800, 1073751887, -37800, 10066, -37800, 10070, -37800, 1073751896, -37800, 10078, -37800, 1073751905, -37800, 10132, -37800, 1073751960, -37800, 10159, -37800, 1073751985, -37800, 10174, -37800, 1073752000, -37800, 10186, -37800, 1073752016, -37800, 10219, -37800, 1073752048, -37800, 11034, -37800, 1073752864, -37800, 11043, -37800, 11264, 67063996, 1073753089, -45056, 11310, -45056, 11312, 67063804, 1073753137, -45248, 11358, -45248, 11360, 67063428, 11361, 67063424, 11362, 67063420, 11363, 67063416, 11364, 67063412, 11365, 67063408, 11366, 67063404, 11367, 67063400, 11368, 67063396, 11369, 67063392, 11370, 67063388, 11371, 67063384, 11372, 67063380, 11380, -45492, 11381, 67063344, 11382, 67063340, 11383, 67063368, 11392, 67063300, 11393, 67063296, 11394, 67063292, 11395, 67063288, 11396, 67063284, 11397, 67063280, 11398, 67063276, 11399, 67063272, 11400, 67063268, 11401, 67063264, 11402, 67063260, 11403, 67063256, 11404, 67063252, 11405, 67063248, 11406, 67063244, 11407, 67063240, 11408, 67063236, 11409, 67063232, 11410, 67063228, 11411, 67063224, 11412, 67063220, 11413, 67063216, 11414, 67063212, 11415, 67063208, 11416, 67063204, 11417, 67063200, 11418, 67063196, 11419, 67063192, 11420, 67063188, 11421, 67063184, 11422, 67063180, 11423, 67063176, 11424, 67063172, 11425, 67063168, 11426, 67063164, 11427, 67063160, 11428, 67063156, 11429, 67063152, 11430, 67063148, 11431, 67063144, 11432, 67063140, 11433, 67063136, 11434, 67063132, 11435, 67063128, 11436, 67063124, 11437, 67063120, 11438, 67063116, 11439, 67063112, 11440, 67063108, 11441, 67063104, 11442, 67063100, 11443, 67063096, 11444, 67063092, 11445, 67063088, 11446, 67063084, 11447, 67063080, 11448, 67063076, 11449, 67063072, 11450, 67063068, 11451, 67063064, 11452, 67063060, 11453, 67063056, 11454, 67063052, 11455, 67063048, 11456, 67063044, 11457, 67063040, 11458, 67063036, 11459, 67063032, 11460, 67063028, 11461, 67063024, 11462, 67063020, 11463, 67063016, 11464, 67063012, 11465, 67063008, 11466, 67063004, 11467, 67063000, 11468, 67062996, 11469, 67062992, 11470, 67062988, 11471, 67062984, 11472, 67062980, 11473, 67062976, 11474, 67062972, 11475, 67062968, 11476, 67062964, 11477, 67062960, 11478, 67062956, 11479, 67062952, 11480, 67062948, 11481, 67062944, 11482, 67062940, 11483, 67062936, 11484, 67062932, 11485, 67062928, 11486, 67062924, 11487, 67062920, 11488, 67062916, 11489, 67062912, 11490, 67062908, 11491, 67062904, 11492, 67063008, 1073753317, -45968, 11498, -45968, 1073753337, -45968, 11519, -45968, 11520, 67062936, 1073753345, -46080, 11557, -46080, 1073753392, -46232, 11621, -46232, 11631, -46232, 1073753472, -46232, 11670, -46232, 1073753504, -46232, 11686, -46232, 1073753512, -46232, 11694, -46232, 1073753520, -46232, 11702, -46232, 1073753528, -46232, 11710, -46232, 1073753536, -46232, 11718, -46232, 1073753544, -46232, 11726, -46232, 1073753552, -46232, 11734, -46232, 1073753560, -46232, 11742, -46232, 1073753600, -46232, 11799, -46232, 1073753628, -46232, 11805, -46232, 1073753728, -46232, 11929, -46232, 1073753755, -46232, 12019, -46232, 1073753856, -46232, 12245, -46232, 1073754096, -46232, 12283, -46232, 1073754112, -46232, 12351, -46232, 1073754177, -46232, 12438, -46232, 1073754265, -46232, 12543, -46232, 1073754373, -46232, 12588, -46232, 1073754417, -46232, 12686, -46232, 1073754512, -46232, 12727, -46232, 1073754560, -46232, 12751, -46232, 1073754608, -46232, 12830, -46232, 1073754656, -46232, 12867, -46232, 1073754704, -46232, 13054, -46232, 1073754880, -46232, 16953, -46232, 16954, 67041052, 16955, 67041056, 1073758780, -67820, 16957, -67820, 16958, 67041036, 16959, 67215248, 1073758784, -67836, 19893, -67836, 1073761728, -67836, 32767, -67836 }; // NOLINT
+static const MultiCharacterSpecialCase<1> kCanonicalizationRangeMultiStrings1[] = { {0, {0}} }; // NOLINT
+static const uint16_t kCanonicalizationRangeTable1Size = 94;
+static const int32_t kCanonicalizationRangeTable1[188] = { 1073741824, -67836, 8123, -67836, 1073750016, -67836, 9356, -67836, 1073751184, -67836, 9414, -67836, 1073751808, -67836, 10010, -67836, 1073751840, -67836, 10017, -67836, 1073752064, -67836, 10283, -67836, 1073752128, -67836, 10359, -67836, 1073753088, -67836, 22435, -67836, 1073764352, -67836, 27745, -67836, 27746, 66866812, 27747, 66866808, 27748, 66866804, 27749, 66885980, 1073769574, -242068, 31277, -242068, 1073773104, -242068, 31338, -242068, 1073773168, -242068, 31449, -242068, 1073773312, -242068, 31494, -242068, 1073773331, -242068, 31511, -242068, 1073773341, -242068, 31542, -242068, 1073773368, -242068, 31548, -242068, 31550, -242068, 1073773376, -242068, 31553, -242068, 1073773379, -242068, 31556, -242068, 1073773382, -242068, 31665, -242068, 1073773523, -242068, 32063, -242068, 1073773904, -242068, 32143, -242068, 1073773970, -242068, 32199, -242068, 1073774064, -242068, 32253, -242068, 1073774080, -242068, 32281, -242068, 1073774112, -242068, 32291, -242068, 1073774128, -242068, 32338, -242068, 1073774164, -242068, 32358, -242068, 1073774184, -242068, 32363, -242068, 1073774192, -242068, 32372, -242068, 1073774198, -242068, 32508, -242068, 32511, -242068, 1073774337, -242068, 32544, -242068, 32545, 66847716, 1073774370, -261252, 32570, -261252, 32571, 66847532, 1073774396, -261356, 32576, -261356, 32577, 66847588, 1073774402, -261380, 32602, -261380, 32603, 66848040, 1073774428, -261484, 32702, -261484, 1073774530, -261484, 32711, -261484, 1073774538, -261484, 32719, -261484, 1073774546, -261484, 32727, -261484, 1073774554, -261484, 32732, -261484, 1073774560, -261484, 32742, -261484, 1073774568, -261484, 32750, -261484, 1073774585, -261484, 32765, -261484 }; // NOLINT
+int CanonicalizationRange::Convert(uchar c,
+                      uchar n,
+                      uchar* result,
+                      bool* allow_caching_ptr) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupMapping(kCanonicalizationRangeTable0,
+                                     kCanonicalizationRangeTable0Size,
+                                     kCanonicalizationRangeMultiStrings0,
+                                     c,
+                                     n,
+                                     result,
+                                     allow_caching_ptr);
+    case 1: return LookupMapping(kCanonicalizationRangeTable1,
+                                     kCanonicalizationRangeTable1Size,
+                                     kCanonicalizationRangeMultiStrings1,
+                                     c,
+                                     n,
+                                     result,
+                                     allow_caching_ptr);
+    default: return 0;
+  }
+}
+
 
 uchar UnicodeData::kMaxCodePoint = 1114109;
 
 int UnicodeData::GetByteCount() {
-  return 0 + (sizeof(uint16_t) * kUppercaseTable0Size) + (sizeof(uint16_t) * kUppercaseTable1Size) + (sizeof(uint16_t) * kUppercaseTable2Size) + (sizeof(uint16_t) * kUppercaseTable3Size) + (sizeof(uint16_t) * kLowercaseTable0Size) + (sizeof(uint16_t) * kLowercaseTable1Size) + (sizeof(uint16_t) * kLowercaseTable2Size) + (sizeof(uint16_t) * kLowercaseTable3Size) + (sizeof(uint16_t) * kLetterTable0Size) + (sizeof(uint16_t) * kLetterTable1Size) + (sizeof(uint16_t) * kLetterTable2Size) + (sizeof(uint16_t) * kLetterTable3Size) + (sizeof(uint16_t) * kLetterTable4Size) + (sizeof(uint16_t) * kLetterTable5Size) + (sizeof(uint16_t) * kSpaceTable0Size) + (sizeof(uint16_t) * kTitlecaseTable0Size) + (sizeof(uint16_t) * kNumberTable0Size) + (sizeof(uint16_t) * kNumberTable1Size) + (sizeof(uint16_t) * kNumberTable2Size) + (sizeof(uint16_t) * kNumberTable3Size) + (sizeof(uint16_t) * kDecimalDigitTable0Size) + (sizeof(uint16_t) * kDecimalDigitTable1Size) + (sizeof(uint16_t) * kDecimalDigitTable2Size) + (sizeof(uint16_t) * kDecimalDigitTable3Size) + (sizeof(uint16_t) * kIdeographicTable0Size) + (sizeof(uint16_t) * kIdeographicTable1Size) + (sizeof(uint16_t) * kIdeographicTable4Size) + (sizeof(uint16_t) * kIdeographicTable5Size) + (sizeof(uint16_t) * kWhiteSpaceTable0Size) + (sizeof(uint16_t) * kHexDigitTable0Size) + (sizeof(uint16_t) * kHexDigitTable1Size) + (sizeof(uint16_t) * kAsciiHexDigitTable0Size) + (sizeof(uint16_t) * kBidiControlTable0Size) + (sizeof(uint16_t) * kJoinControlTable0Size) + (sizeof(uint16_t) * kDashTable0Size) + (sizeof(uint16_t) * kDashTable1Size) + (sizeof(uint16_t) * kHyphenTable0Size) + (sizeof(uint16_t) * kHyphenTable1Size) + (sizeof(uint16_t) * kLineTerminatorTable0Size) + (sizeof(uint16_t) * kRegExpSpecialCharTable0Size) + (sizeof(uint16_t) * kCombiningMarkTable0Size) + (sizeof(uint16_t) * kCombiningMarkTable1Size) + (sizeof(uint16_t) * kCombiningMarkTable2Size) + (sizeof(uint16_t) * kCombiningMarkTable3Size) + (sizeof(uint16_t) * kCombiningMarkTable28Size) + (sizeof(uint16_t) * kConnectorPunctuationTable0Size) + (sizeof(uint16_t) * kConnectorPunctuationTable1Size) + (sizeof(uint16_t) * kToLowercaseTable0Size) + (sizeof(uint16_t) * kToLowercaseTable1Size) + (sizeof(uint16_t) * kToLowercaseTable2Size) + (sizeof(uint16_t) * kToUppercaseTable0Size) + (sizeof(uint16_t) * kToUppercaseTable1Size) + (sizeof(uint16_t) * kToUppercaseTable2Size); // NOLINT
+  return 0 + (sizeof(uint16_t) * kUppercaseTable0Size) + (sizeof(uint16_t) * kUppercaseTable1Size) + (sizeof(uint16_t) * kUppercaseTable2Size) + (sizeof(uint16_t) * kUppercaseTable3Size) + (sizeof(uint16_t) * kLowercaseTable0Size) + (sizeof(uint16_t) * kLowercaseTable1Size) + (sizeof(uint16_t) * kLowercaseTable2Size) + (sizeof(uint16_t) * kLowercaseTable3Size) + (sizeof(uint16_t) * kLetterTable0Size) + (sizeof(uint16_t) * kLetterTable1Size) + (sizeof(uint16_t) * kLetterTable2Size) + (sizeof(uint16_t) * kLetterTable3Size) + (sizeof(uint16_t) * kLetterTable4Size) + (sizeof(uint16_t) * kLetterTable5Size) + (sizeof(uint16_t) * kSpaceTable0Size) + (sizeof(uint16_t) * kNumberTable0Size) + (sizeof(uint16_t) * kNumberTable1Size) + (sizeof(uint16_t) * kNumberTable2Size) + (sizeof(uint16_t) * kNumberTable3Size) + (sizeof(uint16_t) * kWhiteSpaceTable0Size) + (sizeof(uint16_t) * kLineTerminatorTable0Size) + (sizeof(uint16_t) * kCombiningMarkTable0Size) + (sizeof(uint16_t) * kCombiningMarkTable1Size) + (sizeof(uint16_t) * kCombiningMarkTable2Size) + (sizeof(uint16_t) * kCombiningMarkTable3Size) + (sizeof(uint16_t) * kCombiningMarkTable28Size) + (sizeof(uint16_t) * kConnectorPunctuationTable0Size) + (sizeof(uint16_t) * kConnectorPunctuationTable1Size) + (sizeof(uint16_t) * kToLowercaseTable0Size) + (sizeof(uint16_t) * kToLowercaseTable1Size) + (sizeof(uint16_t) * kToLowercaseTable2Size) + (sizeof(uint16_t) * kToUppercaseTable0Size) + (sizeof(uint16_t) * kToUppercaseTable1Size) + (sizeof(uint16_t) * kToUppercaseTable2Size) + (sizeof(uint16_t) * kEcma262CanonicalizeTable0Size) + (sizeof(uint16_t) * kEcma262CanonicalizeTable1Size) + (sizeof(uint16_t) * kEcma262CanonicalizeTable2Size) + (sizeof(uint16_t) * kEcma262UnCanonicalizeTable0Size) + (sizeof(uint16_t) * kEcma262UnCanonicalizeTable1Size) + (sizeof(uint16_t) * kEcma262UnCanonicalizeTable2Size) + (sizeof(uint16_t) * kCanonicalizationRangeTable0Size) + (sizeof(uint16_t) * kCanonicalizationRangeTable1Size); // NOLINT
 }
 
 }  // namespace unicode
index fd7dfbc..86fd498 100644 (file)
@@ -44,7 +44,7 @@ typedef unsigned char byte;
  * The max length of the result of converting the case of a single
  * character.
  */
-static const int kMaxCaseConvertedSize = 3;
+static const int kMaxMappingSize = 4;
 
 template <class T, int size = 256>
 class Predicate {
@@ -80,12 +80,13 @@ class Mapping {
   friend class Test;
   int CalculateValue(uchar c, uchar n, uchar* result);
   struct CacheEntry {
-    inline CacheEntry() : code_point_(0), offset_(0) { }
+    inline CacheEntry() : code_point_(kNoChar), offset_(0) { }
     inline CacheEntry(uchar code_point, signed offset)
       : code_point_(code_point),
         offset_(offset) { }
-    uchar code_point_ : 21;
-    signed offset_ : 11;
+    uchar code_point_;
+    signed offset_;
+    static const int kNoChar = (1 << 21) - 1;
   };
   static const int kSize = size;
   static const int kMask = kSize - 1;
@@ -222,45 +223,15 @@ struct Letter {
 struct Space {
   static bool Is(uchar c);
 };
-struct Titlecase {
-  static bool Is(uchar c);
-};
 struct Number {
   static bool Is(uchar c);
 };
-struct DecimalDigit {
-  static bool Is(uchar c);
-};
-struct Ideographic {
-  static bool Is(uchar c);
-};
 struct WhiteSpace {
   static bool Is(uchar c);
 };
-struct HexDigit {
-  static bool Is(uchar c);
-};
-struct AsciiHexDigit {
-  static bool Is(uchar c);
-};
-struct BidiControl {
-  static bool Is(uchar c);
-};
-struct JoinControl {
-  static bool Is(uchar c);
-};
-struct Dash {
-  static bool Is(uchar c);
-};
-struct Hyphen {
-  static bool Is(uchar c);
-};
 struct LineTerminator {
   static bool Is(uchar c);
 };
-struct RegExpSpecialChar {
-  static bool Is(uchar c);
-};
 struct CombiningMark {
   static bool Is(uchar c);
 };
@@ -268,12 +239,35 @@ struct ConnectorPunctuation {
   static bool Is(uchar c);
 };
 struct ToLowercase {
+  static const int kMaxWidth = 3;
   static int Convert(uchar c,
                      uchar n,
                      uchar* result,
                      bool* allow_caching_ptr);
 };
 struct ToUppercase {
+  static const int kMaxWidth = 3;
+  static int Convert(uchar c,
+                     uchar n,
+                     uchar* result,
+                     bool* allow_caching_ptr);
+};
+struct Ecma262Canonicalize {
+  static const int kMaxWidth = 1;
+  static int Convert(uchar c,
+                     uchar n,
+                     uchar* result,
+                     bool* allow_caching_ptr);
+};
+struct Ecma262UnCanonicalize {
+  static const int kMaxWidth = 4;
+  static int Convert(uchar c,
+                     uchar n,
+                     uchar* result,
+                     bool* allow_caching_ptr);
+};
+struct CanonicalizationRange {
+  static const int kMaxWidth = 1;
   static int Convert(uchar c,
                      uchar n,
                      uchar* result,
index 9f24079..a1e14f9 100644 (file)
@@ -83,6 +83,23 @@ static inline T RoundUp(T x, int m) {
 }
 
 
+template <typename T>
+static int Spaceship(const T& a, const T& b) {
+  if (a == b)
+    return 0;
+  else if (a < b)
+    return -1;
+  else
+    return 1;
+}
+
+
+template <typename T>
+static int PointerSpaceship(const T* a, const T* b) {
+  return Spaceship<T>(*a, *b);
+}
+
+
 // Returns the smallest power of two which is >= x. If you pass in a
 // number that is already a power of two, it is returned as is.
 uint32_t RoundUpToPowerOf2(uint32_t x);
@@ -283,6 +300,15 @@ class Vector {
     return Vector<T>(NewArray<T>(length), length);
   }
 
+  // Returns a vector using the same backing storage as this one,
+  // spanning from and including 'from', to but not including 'to'.
+  Vector<T> SubVector(int from, int to) {
+    ASSERT(from < length_);
+    ASSERT(to <= length_);
+    ASSERT(from < to);
+    return Vector<T>(start() + from, to - from);
+  }
+
   // Returns the length of the vector.
   int length() const { return length_; }
 
@@ -298,6 +324,10 @@ class Vector {
     return start_[index];
   }
 
+  T& first() { return start_[0]; }
+
+  T& last() { return start_[length_ - 1]; }
+
   // Returns a clone of this vector with a new backing store.
   Vector<T> Clone() const {
     T* result = NewArray<T>(length_);
@@ -305,6 +335,18 @@ class Vector {
     return Vector<T>(result, length_);
   }
 
+  void Sort(int (*cmp)(const T*, const T*)) {
+    typedef int (*RawComparer)(const void*, const void*);
+    qsort(start(),
+          length(),
+          sizeof(T),
+          reinterpret_cast<RawComparer>(cmp));
+  }
+
+  void Sort() {
+    Sort(PointerSpaceship<T>);
+  }
+
   // Releases the array underlying this vector. Once disposed the
   // vector is empty.
   void Dispose() {
@@ -465,6 +507,58 @@ static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
   }
 }
 
+
+static inline int Load16(const byte* pc) {
+#ifdef CAN_READ_UNALIGNED
+  return *reinterpret_cast<const uint16_t*>(pc);
+#else
+  uint32_t word;
+  word  = pc[1];
+  word |= pc[0] << 8;
+  return word;
+#endif
+}
+
+
+static inline int Load32(const byte* pc) {
+#ifdef CAN_READ_UNALIGNED
+  return *reinterpret_cast<const uint32_t*>(pc);
+#else
+  uint32_t word;
+  word  = pc[3];
+  word |= pc[2] << 8;
+  word |= pc[1] << 16;
+  word |= pc[0] << 24;
+  return word;
+#endif
+}
+
+
+static inline void Store16(byte* pc, uint16_t value) {
+#ifdef CAN_READ_UNALIGNED
+  *reinterpret_cast<uint16_t*>(pc) = value;
+#else
+  pc[1] = value;
+  pc[0] = value >> 8;
+#endif
+}
+
+
+static inline void Store32(byte* pc, uint32_t value) {
+#ifdef CAN_READ_UNALIGNED
+  *reinterpret_cast<uint32_t*>(pc) = value;
+#else
+  pc[3] = value;
+  pc[2] = value >> 8;
+  pc[1] = value >> 16;
+  pc[0] = value >> 24;
+#endif
+}
+
+
+
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_UTILS_H_
index 2ac13c4..c2a96f2 100644 (file)
@@ -38,7 +38,7 @@ SOURCES = {
     'test-ast.cc', 'test-heap.cc', 'test-utils.cc', 'test-compiler.cc',
     'test-spaces.cc', 'test-mark-compact.cc', 'test-lock.cc',
     'test-conversions.cc', 'test-strings.cc', 'test-serialize.cc',
-    'test-decls.cc', 'test-alloc.cc'
+    'test-decls.cc', 'test-alloc.cc', 'test-regexp.cc'
   ],
   'arch:arm':  ['test-assembler-arm.cc', 'test-disasm-arm.cc'],
   'arch:ia32': ['test-assembler-ia32.cc', 'test-disasm-ia32.cc'],
diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc
new file mode 100644 (file)
index 0000000..41fcd7d
--- /dev/null
@@ -0,0 +1,922 @@
+// Copyright 2006-2008 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 <stdlib.h>
+#include <set>
+
+#include "v8.h"
+
+#include "cctest.h"
+#include "zone-inl.h"
+#include "parser.h"
+#include "ast.h"
+#include "jsregexp-inl.h"
+#include "assembler-irregexp.h"
+#include "regexp-macro-assembler.h"
+#include "regexp-macro-assembler-irregexp.h"
+#include "regexp-macro-assembler-ia32.h"
+#include "interpreter-irregexp.h"
+
+
+using namespace v8::internal;
+
+
+static SmartPointer<const char> Parse(const char* input) {
+  v8::HandleScope scope;
+  ZoneScope zone_scope(DELETE_ON_EXIT);
+  FlatStringReader reader(CStrVector(input));
+  RegExpParseResult result;
+  CHECK(v8::internal::ParseRegExp(&reader, &result));
+  CHECK(result.tree != NULL);
+  CHECK(result.error.is_null());
+  SmartPointer<const char> output = result.tree->ToString();
+  return output;
+}
+
+static bool ParseEscapes(const char* input) {
+  v8::HandleScope scope;
+  unibrow::Utf8InputBuffer<> buffer(input, strlen(input));
+  ZoneScope zone_scope(DELETE_ON_EXIT);
+  FlatStringReader reader(CStrVector(input));
+  RegExpParseResult result;
+  CHECK(v8::internal::ParseRegExp(&reader, &result));
+  CHECK(result.tree != NULL);
+  CHECK(result.error.is_null());
+  return result.has_character_escapes;
+}
+
+
+#define CHECK_PARSE_EQ(input, expected) CHECK_EQ(expected, *Parse(input))
+#define CHECK_ESCAPES(input, has_escapes) CHECK_EQ(has_escapes, \
+                                                   ParseEscapes(input));
+
+TEST(Parser) {
+  V8::Initialize(NULL);
+  CHECK_PARSE_EQ("abc", "'abc'");
+  CHECK_PARSE_EQ("", "%");
+  CHECK_PARSE_EQ("abc|def", "(| 'abc' 'def')");
+  CHECK_PARSE_EQ("abc|def|ghi", "(| 'abc' 'def' 'ghi')");
+  CHECK_PARSE_EQ("^xxx$", "(: @^i 'xxx' @$i)");
+  CHECK_PARSE_EQ("ab\\b\\d\\bcd", "(: 'ab' @b [0-9] @b 'cd')");
+  CHECK_PARSE_EQ("\\w|\\d", "(| [0-9 A-Z _ a-z] [0-9])");
+  CHECK_PARSE_EQ("a*", "(# 0 - g 'a')");
+  CHECK_PARSE_EQ("a*?", "(# 0 - n 'a')");
+  CHECK_PARSE_EQ("abc+", "(: 'ab' (# 1 - g 'c'))");
+  CHECK_PARSE_EQ("abc+?", "(: 'ab' (# 1 - n 'c'))");
+  CHECK_PARSE_EQ("xyz?", "(: 'xy' (# 0 1 g 'z'))");
+  CHECK_PARSE_EQ("xyz??", "(: 'xy' (# 0 1 n 'z'))");
+  CHECK_PARSE_EQ("xyz{0,1}", "(: 'xy' (# 0 1 g 'z'))");
+  CHECK_PARSE_EQ("xyz{0,1}?", "(: 'xy' (# 0 1 n 'z'))");
+  CHECK_PARSE_EQ("xyz{93}", "(: 'xy' (# 93 93 g 'z'))");
+  CHECK_PARSE_EQ("xyz{93}?", "(: 'xy' (# 93 93 n 'z'))");
+  CHECK_PARSE_EQ("xyz{1,32}", "(: 'xy' (# 1 32 g 'z'))");
+  CHECK_PARSE_EQ("xyz{1,32}?", "(: 'xy' (# 1 32 n 'z'))");
+  CHECK_PARSE_EQ("xyz{1,}", "(: 'xy' (# 1 - g 'z'))");
+  CHECK_PARSE_EQ("xyz{1,}?", "(: 'xy' (# 1 - n 'z'))");
+  CHECK_PARSE_EQ("a\\fb\\nc\\rd\\te\\vf", "'a\\x0cb\\x0ac\\x0dd\\x09e\\x0bf'");
+  CHECK_PARSE_EQ("a\\nb\\bc", "(: 'a\\x0ab' @b 'c')");
+  CHECK_PARSE_EQ("(?:foo)", "'foo'");
+  CHECK_PARSE_EQ("(?: foo )", "' foo '");
+  CHECK_PARSE_EQ("(foo|bar|baz)", "(^ (| 'foo' 'bar' 'baz'))");
+  CHECK_PARSE_EQ("foo|(bar|baz)|quux", "(| 'foo' (^ (| 'bar' 'baz')) 'quux')");
+  CHECK_PARSE_EQ("foo(?=bar)baz", "(: 'foo' (-> + 'bar') 'baz')");
+  CHECK_PARSE_EQ("foo(?!bar)baz", "(: 'foo' (-> - 'bar') 'baz')");
+  CHECK_PARSE_EQ("()", "(^ %)");
+  CHECK_PARSE_EQ("(?=)", "(-> + %)");
+  CHECK_PARSE_EQ("[]", "^[\\x00-\\uffff]");   // Doesn't compile on windows
+  CHECK_PARSE_EQ("[^]", "[\\x00-\\uffff]");   // \uffff isn't in codepage 1252
+  CHECK_PARSE_EQ("[x]", "[x]");
+  CHECK_PARSE_EQ("[xyz]", "[x y z]");
+  CHECK_PARSE_EQ("[a-zA-Z0-9]", "[a-z A-Z 0-9]");
+  CHECK_PARSE_EQ("[-123]", "[- 1 2 3]");
+  CHECK_PARSE_EQ("[^123]", "^[1 2 3]");
+  CHECK_PARSE_EQ("]", "']'");
+  CHECK_PARSE_EQ("}", "'}'");
+  CHECK_PARSE_EQ("[a-b-c]", "[a-b - c]");
+  CHECK_PARSE_EQ("[\\d]", "[0-9]");
+  CHECK_PARSE_EQ("[x\\dz]", "[x 0-9 z]");
+  CHECK_PARSE_EQ("[\\d-z]", "[0-9 - z]");
+  CHECK_PARSE_EQ("[\\d-\\d]", "[0-9 - 0-9]");
+  CHECK_PARSE_EQ("\\cj\\cJ\\ci\\cI\\ck\\cK",
+                 "'\\x0a\\x0a\\x09\\x09\\x0b\\x0b'");
+  CHECK_PARSE_EQ("\\c!", "'c!'");
+  CHECK_PARSE_EQ("\\c_", "'c_'");
+  CHECK_PARSE_EQ("\\c~", "'c~'");
+  CHECK_PARSE_EQ("[a\\]c]", "[a ] c]");
+  CHECK_PARSE_EQ("\\[\\]\\{\\}\\(\\)\\%\\^\\#\\ ", "'[]{}()%^# '");
+  CHECK_PARSE_EQ("[\\[\\]\\{\\}\\(\\)\\%\\^\\#\\ ]", "[[ ] { } ( ) % ^ #  ]");
+  CHECK_PARSE_EQ("\\0", "'\\x00'");
+  CHECK_PARSE_EQ("\\8", "'8'");
+  CHECK_PARSE_EQ("\\9", "'9'");
+  CHECK_PARSE_EQ("\\11", "'\\x09'");
+  CHECK_PARSE_EQ("\\11a", "'\\x09a'");
+  CHECK_PARSE_EQ("\\011", "'\\x09'");
+  CHECK_PARSE_EQ("\\00011", "'\\x0011'");
+  CHECK_PARSE_EQ("\\118", "'\\x098'");
+  CHECK_PARSE_EQ("\\111", "'I'");
+  CHECK_PARSE_EQ("\\1111", "'I1'");
+  CHECK_PARSE_EQ("(x)(x)(x)\\1", "(: (^ 'x') (^ 'x') (^ 'x') (<- 1))");
+  CHECK_PARSE_EQ("(x)(x)(x)\\2", "(: (^ 'x') (^ 'x') (^ 'x') (<- 2))");
+  CHECK_PARSE_EQ("(x)(x)(x)\\3", "(: (^ 'x') (^ 'x') (^ 'x') (<- 3))");
+  CHECK_PARSE_EQ("(x)(x)(x)\\4", "(: (^ 'x') (^ 'x') (^ 'x') '\\x04')");
+  CHECK_PARSE_EQ("(x)(x)(x)\\1*", "(: (^ 'x') (^ 'x') (^ 'x')"
+                               " (# 0 - g (<- 1)))");
+  CHECK_PARSE_EQ("(x)(x)(x)\\2*", "(: (^ 'x') (^ 'x') (^ 'x')"
+                               " (# 0 - g (<- 2)))");
+  CHECK_PARSE_EQ("(x)(x)(x)\\3*", "(: (^ 'x') (^ 'x') (^ 'x')"
+                               " (# 0 - g (<- 3)))");
+  CHECK_PARSE_EQ("(x)(x)(x)\\4*", "(: (^ 'x') (^ 'x') (^ 'x')"
+                               " (# 0 - g '\\x04'))");
+  CHECK_PARSE_EQ("(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\\10",
+              "(: (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x')"
+              " (^ 'x') (^ 'x') (^ 'x') (^ 'x') (<- 10))");
+  CHECK_PARSE_EQ("(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\\11",
+              "(: (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x')"
+              " (^ 'x') (^ 'x') (^ 'x') (^ 'x') '\\x09')");
+  CHECK_PARSE_EQ("(a)\\1", "(: (^ 'a') (<- 1))");
+  CHECK_PARSE_EQ("(a\\1)", "(^ 'a')");
+  CHECK_PARSE_EQ("(\\1a)", "(^ 'a')");
+  CHECK_PARSE_EQ("\\1(a)", "(^ 'a')");
+  CHECK_PARSE_EQ("(?!(a))\\1", "(-> - (^ 'a'))");
+  CHECK_PARSE_EQ("(?!\\1(a\\1)\\1)\\1", "(-> - (: (^ 'a') (<- 1)))");
+  CHECK_PARSE_EQ("[\\0]", "[\\x00]");
+  CHECK_PARSE_EQ("[\\11]", "[\\x09]");
+  CHECK_PARSE_EQ("[\\11a]", "[\\x09 a]");
+  CHECK_PARSE_EQ("[\\011]", "[\\x09]");
+  CHECK_PARSE_EQ("[\\00011]", "[\\x00 1 1]");
+  CHECK_PARSE_EQ("[\\118]", "[\\x09 8]");
+  CHECK_PARSE_EQ("[\\111]", "[I]");
+  CHECK_PARSE_EQ("[\\1111]", "[I 1]");
+  CHECK_PARSE_EQ("\\x34", "'\x34'");
+  CHECK_PARSE_EQ("\\x60", "'\x60'");
+  CHECK_PARSE_EQ("\\x3z", "'x3z'");
+  CHECK_PARSE_EQ("\\u0034", "'\x34'");
+  CHECK_PARSE_EQ("\\u003z", "'u003z'");
+  CHECK_PARSE_EQ("foo[z]*", "(: 'foo' (# 0 - g [z]))");
+
+  CHECK_ESCAPES("a", false);
+  CHECK_ESCAPES("a|b", false);
+  CHECK_ESCAPES("a\\n", true);
+  CHECK_ESCAPES("^a", false);
+  CHECK_ESCAPES("a$", false);
+  CHECK_ESCAPES("a\\b!", false);
+  CHECK_ESCAPES("a\\Bb", false);
+  CHECK_ESCAPES("a*", false);
+  CHECK_ESCAPES("a*?", false);
+  CHECK_ESCAPES("a?", false);
+  CHECK_ESCAPES("a??", false);
+  CHECK_ESCAPES("a{0,1}?", false);
+  CHECK_ESCAPES("a{1,1}?", false);
+  CHECK_ESCAPES("a{1,2}?", false);
+  CHECK_ESCAPES("a+?", false);
+  CHECK_ESCAPES("(a)", false);
+  CHECK_ESCAPES("(a)\\1", false);
+  CHECK_ESCAPES("(\\1a)", false);
+  CHECK_ESCAPES("\\1(a)", false);
+  CHECK_ESCAPES("a\\s", false);
+  CHECK_ESCAPES("a\\S", false);
+  CHECK_ESCAPES("a\\d", false);
+  CHECK_ESCAPES("a\\D", false);
+  CHECK_ESCAPES("a\\w", false);
+  CHECK_ESCAPES("a\\W", false);
+  CHECK_ESCAPES("a.", false);
+  CHECK_ESCAPES("a\\q", true);
+  CHECK_ESCAPES("a[a]", false);
+  CHECK_ESCAPES("a[^a]", false);
+  CHECK_ESCAPES("a[a-z]", false);
+  CHECK_ESCAPES("a[\\q]", false);
+  CHECK_ESCAPES("a(?:b)", false);
+  CHECK_ESCAPES("a(?=b)", false);
+  CHECK_ESCAPES("a(?!b)", false);
+  CHECK_ESCAPES("\\x60", true);
+  CHECK_ESCAPES("\\u0060", true);
+  CHECK_ESCAPES("\\cA", true);
+  CHECK_ESCAPES("\\q", true);
+  CHECK_ESCAPES("\\1112", true);
+  CHECK_ESCAPES("\\0", true);
+  CHECK_ESCAPES("(a)\\1", false);
+
+  CHECK_PARSE_EQ("a{}", "'a{}'");
+  CHECK_PARSE_EQ("a{,}", "'a{,}'");
+  CHECK_PARSE_EQ("a{", "'a{'");
+  CHECK_PARSE_EQ("a{z}", "'a{z}'");
+  CHECK_PARSE_EQ("a{1z}", "'a{1z}'");
+  CHECK_PARSE_EQ("a{12z}", "'a{12z}'");
+  CHECK_PARSE_EQ("a{12,", "'a{12,'");
+  CHECK_PARSE_EQ("a{12,3b", "'a{12,3b'");
+  CHECK_PARSE_EQ("{}", "'{}'");
+  CHECK_PARSE_EQ("{,}", "'{,}'");
+  CHECK_PARSE_EQ("{", "'{'");
+  CHECK_PARSE_EQ("{z}", "'{z}'");
+  CHECK_PARSE_EQ("{1z}", "'{1z}'");
+  CHECK_PARSE_EQ("{12z}", "'{12z}'");
+  CHECK_PARSE_EQ("{12,", "'{12,'");
+  CHECK_PARSE_EQ("{12,3b", "'{12,3b'");
+}
+
+TEST(ParserRegression) {
+  CHECK_PARSE_EQ("[A-Z$-][x]", "(! [A-Z $ -] [x])");
+  CHECK_PARSE_EQ("a{3,4*}", "(: 'a{3,' (# 0 - g '4') '}')");
+  CHECK_PARSE_EQ("{", "'{'");
+  CHECK_PARSE_EQ("a|", "(| 'a' %)");
+}
+
+static void ExpectError(const char* input,
+                        const char* expected) {
+  v8::HandleScope scope;
+  ZoneScope zone_scope(DELETE_ON_EXIT);
+  FlatStringReader reader(CStrVector(input));
+  RegExpParseResult result;
+  CHECK_EQ(false, v8::internal::ParseRegExp(&reader, &result));
+  CHECK(result.tree == NULL);
+  CHECK(!result.error.is_null());
+  SmartPointer<char> str = result.error->ToCString(ALLOW_NULLS);
+  CHECK_EQ(expected, *str);
+}
+
+
+TEST(Errors) {
+  V8::Initialize(NULL);
+  const char* kEndBackslash = "\\ at end of pattern";
+  ExpectError("\\", kEndBackslash);
+  const char* kUnterminatedGroup = "Unterminated group";
+  ExpectError("(foo", kUnterminatedGroup);
+  const char* kInvalidGroup = "Invalid group";
+  ExpectError("(?", kInvalidGroup);
+  const char* kUnterminatedCharacterClass = "Unterminated character class";
+  ExpectError("[", kUnterminatedCharacterClass);
+  ExpectError("[a-", kUnterminatedCharacterClass);
+  const char* kIllegalCharacterClass = "Illegal character class";
+  ExpectError("[a-\\w]", kIllegalCharacterClass);
+  const char* kEndControl = "\\c at end of pattern";
+  ExpectError("\\c", kEndControl);
+  const char* kNothingToRepeat = "Nothing to repeat";
+  ExpectError("*", kNothingToRepeat);
+  ExpectError("?", kNothingToRepeat);
+  ExpectError("+", kNothingToRepeat);
+  ExpectError("{1}", kNothingToRepeat);
+  ExpectError("{1,2}", kNothingToRepeat);
+  ExpectError("{1,}", kNothingToRepeat);
+}
+
+
+static bool IsDigit(uc16 c) {
+  return ('0' <= c && c <= '9');
+}
+
+
+static bool NotDigit(uc16 c) {
+  return !IsDigit(c);
+}
+
+
+static bool IsWhiteSpace(uc16 c) {
+  switch (c) {
+    case 0x09:
+    case 0x0A:
+    case 0x0B:
+    case 0x0C:
+    case 0x0d:
+    case 0x20:
+    case 0xA0:
+    case 0x2028:
+    case 0x2029:
+      return true;
+    default:
+      return unibrow::Space::Is(c);
+  }
+}
+
+
+static bool NotWhiteSpace(uc16 c) {
+  return !IsWhiteSpace(c);
+}
+
+
+static bool IsWord(uc16 c) {
+  return ('a' <= c && c <= 'z')
+      || ('A' <= c && c <= 'Z')
+      || ('0' <= c && c <= '9')
+      || (c == '_');
+}
+
+
+static bool NotWord(uc16 c) {
+  return !IsWord(c);
+}
+
+
+static bool Dot(uc16 c) {
+  switch (c) {
+    //   CR           LF           LS           PS
+    case 0x000A: case 0x000D: case 0x2028: case 0x2029:
+      return false;
+    default:
+      return true;
+  }
+}
+
+
+static void TestCharacterClassEscapes(uc16 c, bool (pred)(uc16 c)) {
+  ZoneScope scope(DELETE_ON_EXIT);
+  ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2);
+  CharacterRange::AddClassEscape(c, ranges);
+  for (unsigned i = 0; i < (1 << 16); i++) {
+    bool in_class = false;
+    for (int j = 0; !in_class && j < ranges->length(); j++) {
+      CharacterRange& range = ranges->at(j);
+      in_class = (range.from() <= i && i <= range.to());
+    }
+    CHECK_EQ(pred(i), in_class);
+  }
+}
+
+
+TEST(CharacterClassEscapes) {
+  TestCharacterClassEscapes('.', Dot);
+  TestCharacterClassEscapes('d', IsDigit);
+  TestCharacterClassEscapes('D', NotDigit);
+  TestCharacterClassEscapes('s', IsWhiteSpace);
+  TestCharacterClassEscapes('S', NotWhiteSpace);
+  TestCharacterClassEscapes('w', IsWord);
+  TestCharacterClassEscapes('W', NotWord);
+}
+
+
+static RegExpNode* Compile(const char* input) {
+  FlatStringReader reader(CStrVector(input));
+  RegExpParseResult result;
+  if (!v8::internal::ParseRegExp(&reader, &result))
+    return NULL;
+  RegExpNode* node = NULL;
+  RegExpEngine::Compile(&result, &node, false);
+  return node;
+}
+
+
+static void Execute(const char* input,
+                    const char* str,
+                    bool dot_output = false) {
+  v8::HandleScope scope;
+  ZoneScope zone_scope(DELETE_ON_EXIT);
+  RegExpNode* node = Compile(input);
+  USE(node);
+#ifdef DEBUG
+  if (dot_output) {
+    RegExpEngine::DotPrint(input, node);
+    exit(0);
+  }
+#endif  // DEBUG
+}
+
+
+TEST(Execution) {
+  V8::Initialize(NULL);
+  Execute(".*?(?:a[bc]d|e[fg]h)", "xxxabbegh");
+  Execute(".*?(?:a[bc]d|e[fg]h)", "xxxabbefh");
+  Execute(".*?(?:a[bc]d|e[fg]h)", "xxxabbefd");
+}
+
+
+class TestConfig {
+ public:
+  typedef int Key;
+  typedef int Value;
+  static const int kNoKey;
+  static const int kNoValue;
+  static inline int Compare(int a, int b) {
+    if (a < b)
+      return -1;
+    else if (a > b)
+      return 1;
+    else
+      return 0;
+  }
+};
+
+
+const int TestConfig::kNoKey = 0;
+const int TestConfig::kNoValue = 0;
+
+
+static int PseudoRandom(int i, int j) {
+  return ~(~((i * 781) ^ (j * 329)));
+}
+
+
+TEST(SplayTreeSimple) {
+  static const int kLimit = 1000;
+  ZoneScope zone_scope(DELETE_ON_EXIT);
+  ZoneSplayTree<TestConfig> tree;
+  std::set<int> seen;
+#define CHECK_MAPS_EQUAL() do {                                      \
+    for (int k = 0; k < kLimit; k++)                                 \
+      CHECK_EQ(seen.find(k) != seen.end(), tree.Find(k, &loc));      \
+  } while (false)
+  for (int i = 0; i < 50; i++) {
+    for (int j = 0; j < 50; j++) {
+      int next = PseudoRandom(i, j) % kLimit;
+      if (seen.find(next) != seen.end()) {
+        // We've already seen this one.  Check the value and remove
+        // it.
+        ZoneSplayTree<TestConfig>::Locator loc;
+        CHECK(tree.Find(next, &loc));
+        CHECK_EQ(next, loc.key());
+        CHECK_EQ(3 * next, loc.value());
+        tree.Remove(next);
+        seen.erase(next);
+        CHECK_MAPS_EQUAL();
+      } else {
+        // Check that it wasn't there already and then add it.
+        ZoneSplayTree<TestConfig>::Locator loc;
+        CHECK(!tree.Find(next, &loc));
+        CHECK(tree.Insert(next, &loc));
+        CHECK_EQ(next, loc.key());
+        loc.set_value(3 * next);
+        seen.insert(next);
+        CHECK_MAPS_EQUAL();
+      }
+      int val = PseudoRandom(j, i) % kLimit;
+      for (int k = val; k >= 0; k--) {
+        if (seen.find(val) != seen.end()) {
+          ZoneSplayTree<TestConfig>::Locator loc;
+          CHECK(tree.FindGreatestLessThan(val, &loc));
+          CHECK_EQ(loc.key(), val);
+          break;
+        }
+      }
+      val = PseudoRandom(i + j, i - j) % kLimit;
+      for (int k = val; k < kLimit; k++) {
+        if (seen.find(val) != seen.end()) {
+          ZoneSplayTree<TestConfig>::Locator loc;
+          CHECK(tree.FindLeastGreaterThan(val, &loc));
+          CHECK_EQ(loc.key(), val);
+          break;
+        }
+      }
+    }
+  }
+}
+
+
+TEST(DispatchTableConstruction) {
+  // Initialize test data.
+  static const int kLimit = 1000;
+  static const int kRangeCount = 8;
+  static const int kRangeSize = 16;
+  uc16 ranges[kRangeCount][2 * kRangeSize];
+  for (int i = 0; i < kRangeCount; i++) {
+    Vector<uc16> range(ranges[i], 2 * kRangeSize);
+    for (int j = 0; j < 2 * kRangeSize; j++) {
+      range[j] = PseudoRandom(i + 25, j + 87) % kLimit;
+    }
+    range.Sort();
+    for (int j = 1; j < 2 * kRangeSize; j++) {
+      CHECK(range[j-1] <= range[j]);
+    }
+  }
+  // Enter test data into dispatch table.
+  ZoneScope zone_scope(DELETE_ON_EXIT);
+  DispatchTable table;
+  for (int i = 0; i < kRangeCount; i++) {
+    uc16* range = ranges[i];
+    for (int j = 0; j < 2 * kRangeSize; j += 2)
+      table.AddRange(CharacterRange(range[j], range[j + 1]), i);
+  }
+  // Check that the table looks as we would expect
+  for (int p = 0; p < kLimit; p++) {
+    OutSet* outs = table.Get(p);
+    for (int j = 0; j < kRangeCount; j++) {
+      uc16* range = ranges[j];
+      bool is_on = false;
+      for (int k = 0; !is_on && (k < 2 * kRangeSize); k += 2)
+        is_on = (range[k] <= p && p <= range[k + 1]);
+      CHECK_EQ(is_on, outs->Get(j));
+    }
+  }
+}
+
+
+TEST(Assembler) {
+  V8::Initialize(NULL);
+  byte codes[1024];
+  IrregexpAssembler assembler(Vector<byte>(codes, 1024));
+#define __ assembler.
+  Label advance;
+  Label look_for_foo;
+  Label fail;
+  __ GoTo(&look_for_foo);
+  __ Bind(&advance);
+  __ AdvanceCP(1);
+  __ Bind(&look_for_foo);
+  __ LoadCurrentChar(0, &fail);
+  __ CheckNotCharacter('f', &advance);
+  __ LoadCurrentChar(1, &fail);
+  __ CheckNotCharacter('o', &advance);
+  __ LoadCurrentChar(2, &fail);
+  __ CheckNotCharacter('o', &advance);
+  __ WriteCurrentPositionToRegister(0);
+  __ WriteCurrentPositionToRegister(1, 2);
+  __ Succeed();
+  __ Bind(&fail);
+  __ Fail();
+
+  v8::HandleScope scope;
+  Handle<ByteArray> array = Factory::NewByteArray(assembler.length());
+  assembler.Copy(array->GetDataStartAddress());
+  int captures[2];
+
+  Handle<String> f1 =
+      Factory::NewStringFromAscii(CStrVector("Now is the time"));
+  Handle<String> f1_16 = RegExpImpl::StringToTwoByte(f1);
+  CHECK(!IrregexpInterpreter::Match(array, f1_16, captures, 0));
+
+  Handle<String> f2 = Factory::NewStringFromAscii(CStrVector("foo bar baz"));
+  Handle<String> f2_16 = RegExpImpl::StringToTwoByte(f2);
+  CHECK(IrregexpInterpreter::Match(array, f2_16, captures, 0));
+  CHECK_EQ(0, captures[0]);
+  CHECK_EQ(2, captures[1]);
+
+  Handle<String> f3 = Factory::NewStringFromAscii(CStrVector("tomfoolery"));
+  Handle<String> f3_16 = RegExpImpl::StringToTwoByte(f3);
+  CHECK(IrregexpInterpreter::Match(array, f3_16, captures, 0));
+  CHECK_EQ(3, captures[0]);
+  CHECK_EQ(5, captures[1]);
+}
+
+
+TEST(Assembler2) {
+  V8::Initialize(NULL);
+  byte codes[1024];
+  IrregexpAssembler assembler(Vector<byte>(codes, 1024));
+#define __ assembler.
+  // /^.*foo/
+  Label more_dots;
+  Label unwind_dot;
+  Label failure;
+  Label foo;
+  Label foo_failed;
+  Label dot_match;
+  // ^
+  __ PushCurrentPosition();
+  __ PushRegister(0);
+  __ WriteCurrentPositionToRegister(0);
+  __ PushBacktrack(&failure);
+  __ GoTo(&dot_match);
+  // .*
+  __ Bind(&more_dots);
+  __ AdvanceCP(1);
+  __ Bind(&dot_match);
+  __ PushCurrentPosition();
+  __ PushBacktrack(&unwind_dot);
+  __ LoadCurrentChar(0, &foo);
+  __ CheckNotCharacter('\n', &more_dots);
+  // foo
+  __ Bind(&foo);
+  __ CheckNotCharacter('f', &foo_failed);
+  __ LoadCurrentChar(1, &foo_failed);
+  __ CheckNotCharacter('o', &foo_failed);
+  __ LoadCurrentChar(2, &foo_failed);
+  __ CheckNotCharacter('o', &foo_failed);
+  __ WriteCurrentPositionToRegister(1, 2);
+  __ Succeed();
+  __ Break();
+
+  __ Bind(&foo_failed);
+  __ PopBacktrack();
+  __ Break();
+
+  __ Bind(&unwind_dot);
+  __ PopCurrentPosition();
+  __ LoadCurrentChar(0, &foo_failed);
+  __ GoTo(&foo);
+
+  __ Bind(&failure);
+  __ PopRegister(0);
+  __ PopCurrentPosition();
+  __ Fail();
+
+  v8::HandleScope scope;
+  Handle<ByteArray> array = Factory::NewByteArray(assembler.length());
+  assembler.Copy(array->GetDataStartAddress());
+  int captures[2];
+
+  Handle<String> f1 =
+      Factory::NewStringFromAscii(CStrVector("Now is the time"));
+  Handle<String> f1_16 = RegExpImpl::StringToTwoByte(f1);
+  CHECK(!IrregexpInterpreter::Match(array, f1_16, captures, 0));
+
+  Handle<String> f2 = Factory::NewStringFromAscii(CStrVector("foo bar baz"));
+  Handle<String> f2_16 = RegExpImpl::StringToTwoByte(f2);
+  CHECK(IrregexpInterpreter::Match(array, f2_16, captures, 0));
+  CHECK_EQ(0, captures[0]);
+  CHECK_EQ(2, captures[1]);
+
+  Handle<String> f3 = Factory::NewStringFromAscii(CStrVector("tomfoolery"));
+  Handle<String> f3_16 = RegExpImpl::StringToTwoByte(f3);
+  CHECK(IrregexpInterpreter::Match(array, f3_16, captures, 0));
+  CHECK_EQ(0, captures[0]);
+  CHECK_EQ(5, captures[1]);
+
+  Handle<String> f4 =
+      Factory::NewStringFromAscii(CStrVector("football buffoonery"));
+  Handle<String> f4_16 = RegExpImpl::StringToTwoByte(f4);
+  CHECK(IrregexpInterpreter::Match(array, f4_16, captures, 0));
+  CHECK_EQ(0, captures[0]);
+  CHECK_EQ(14, captures[1]);
+
+  Handle<String> f5 =
+      Factory::NewStringFromAscii(CStrVector("walking\nbarefoot"));
+  Handle<String> f5_16 = RegExpImpl::StringToTwoByte(f5);
+  CHECK(!IrregexpInterpreter::Match(array, f5_16, captures, 0));
+}
+
+
+TEST(MacroAssembler) {
+  V8::Initialize(NULL);
+  byte codes[1024];
+  IrregexpAssembler assembler(Vector<byte>(codes, 1024));
+  RegExpMacroAssemblerIrregexp m(&assembler);
+  // ^f(o)o.
+  Label fail, fail2, start;
+  uc16 foo_chars[3];
+  foo_chars[0] = 'f';
+  foo_chars[1] = 'o';
+  foo_chars[2] = 'o';
+  Vector<const uc16> foo(foo_chars, 3);
+  m.SetRegister(4, 42);
+  m.PushRegister(4);
+  m.AdvanceRegister(4, 42);
+  m.GoTo(&start);
+  m.Fail();
+  m.Bind(&start);
+  m.PushBacktrack(&fail2);
+  m.CheckCharacters(foo, 0, &fail);
+  m.WriteCurrentPositionToRegister(0);
+  m.PushCurrentPosition();
+  m.AdvanceCurrentPosition(3);
+  m.WriteCurrentPositionToRegister(1);
+  m.PopCurrentPosition();
+  m.AdvanceCurrentPosition(1);
+  m.WriteCurrentPositionToRegister(2);
+  m.AdvanceCurrentPosition(1);
+  m.WriteCurrentPositionToRegister(3);
+  m.Succeed();
+
+  m.Bind(&fail);
+  m.Backtrack();
+  m.Succeed();
+
+  m.Bind(&fail2);
+  m.PopRegister(0);
+  m.Fail();
+
+  v8::HandleScope scope;
+
+  Handle<ByteArray> array = Factory::NewByteArray(assembler.length());
+  assembler.Copy(array->GetDataStartAddress());
+  int captures[5];
+
+  Handle<String> f1 =
+      Factory::NewStringFromAscii(CStrVector("foobar"));
+  Handle<String> f1_16 = RegExpImpl::StringToTwoByte(f1);
+  CHECK(IrregexpInterpreter::Match(array, f1_16, captures, 0));
+  CHECK_EQ(0, captures[0]);
+  CHECK_EQ(3, captures[1]);
+  CHECK_EQ(1, captures[2]);
+  CHECK_EQ(2, captures[3]);
+  CHECK_EQ(84, captures[4]);
+
+  Handle<String> f2 =
+      Factory::NewStringFromAscii(CStrVector("barfoo"));
+  Handle<String> f2_16 = RegExpImpl::StringToTwoByte(f2);
+  CHECK(!IrregexpInterpreter::Match(array, f2_16, captures, 0));
+  CHECK_EQ(42, captures[0]);
+}
+
+
+TEST(AddInverseToTable) {
+  static const int kLimit = 1000;
+  static const int kRangeCount = 16;
+  for (int t = 0; t < 10; t++) {
+    ZoneScope zone_scope(DELETE_ON_EXIT);
+    ZoneList<CharacterRange>* ranges =
+        new ZoneList<CharacterRange>(kRangeCount);
+    for (int i = 0; i < kRangeCount; i++) {
+      int from = PseudoRandom(t + 87, i + 25) % kLimit;
+      int to = from + (PseudoRandom(i + 87, t + 25) % (kLimit / 20));
+      if (to > kLimit) to = kLimit;
+      ranges->Add(CharacterRange(from, to));
+    }
+    DispatchTable table;
+    DispatchTableConstructor cons(&table);
+    cons.set_choice_index(0);
+    cons.AddInverse(ranges);
+    for (int i = 0; i < kLimit; i++) {
+      bool is_on = false;
+      for (int j = 0; !is_on && j < kRangeCount; j++)
+        is_on = ranges->at(j).Contains(i);
+      OutSet* set = table.Get(i);
+      CHECK_EQ(is_on, set->Get(0) == false);
+    }
+  }
+  ZoneScope zone_scope(DELETE_ON_EXIT);
+  ZoneList<CharacterRange>* ranges =
+          new ZoneList<CharacterRange>(1);
+  ranges->Add(CharacterRange(0xFFF0, 0xFFFE));
+  DispatchTable table;
+  DispatchTableConstructor cons(&table);
+  cons.set_choice_index(0);
+  cons.AddInverse(ranges);
+  CHECK(!table.Get(0xFFFE)->Get(0));
+  CHECK(table.Get(0xFFFF)->Get(0));
+}
+
+
+static uc32 canonicalize(uc32 c) {
+  unibrow::uchar canon[unibrow::Ecma262Canonicalize::kMaxWidth];
+  int count = unibrow::Ecma262Canonicalize::Convert(c, '\0', canon, NULL);
+  if (count == 0) {
+    return c;
+  } else {
+    CHECK_EQ(1, count);
+    return canon[0];
+  }
+}
+
+
+TEST(LatinCanonicalize) {
+  unibrow::Mapping<unibrow::Ecma262UnCanonicalize> un_canonicalize;
+  for (char lower = 'a'; lower <= 'z'; lower++) {
+    char upper = lower + ('A' - 'a');
+    CHECK_EQ(canonicalize(lower), canonicalize(upper));
+    unibrow::uchar uncanon[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+    int length = un_canonicalize.get(lower, '\0', uncanon);
+    CHECK_EQ(2, length);
+    CHECK_EQ(upper, uncanon[0]);
+    CHECK_EQ(lower, uncanon[1]);
+  }
+  for (uc32 c = 128; c < (1 << 21); c++)
+    CHECK_GE(canonicalize(c), 128);
+  unibrow::Mapping<unibrow::ToUppercase> to_upper;
+  for (uc32 c = 0; c < (1 << 21); c++) {
+    unibrow::uchar upper[unibrow::ToUppercase::kMaxWidth];
+    int length = to_upper.get(c, '\0', upper);
+    if (length == 0) {
+      length = 1;
+      upper[0] = c;
+    }
+    uc32 u = upper[0];
+    if (length > 1 || (c >= 128 && u < 128))
+      u = c;
+    CHECK_EQ(u, canonicalize(c));
+  }
+}
+
+
+TEST(SimplePropagation) {
+  v8::HandleScope scope;
+  ZoneScope zone_scope(DELETE_ON_EXIT);
+  RegExpNode* node = Compile("(a|^b|c)");
+  CHECK(node->info()->determine_start);
+}
+
+
+static uc32 CanonRange(uc32 c) {
+  unibrow::uchar canon[unibrow::CanonicalizationRange::kMaxWidth];
+  int count = unibrow::CanonicalizationRange::Convert(c, '\0', canon, NULL);
+  if (count == 0) {
+    return c;
+  } else {
+    CHECK_EQ(1, count);
+    return canon[0];
+  }
+}
+
+
+TEST(RangeCanonicalization) {
+  ASSERT((CanonRange(0) & CharacterRange::kStartMarker) != 0);
+  // Check that we arrive at the same result when using the basic
+  // range canonicalization primitives as when using immediate
+  // canonicalization.
+  unibrow::Mapping<unibrow::Ecma262UnCanonicalize> un_canonicalize;
+  for (int i = 0; i < CharacterRange::kRangeCanonicalizeMax; i++) {
+    int range = CanonRange(i);
+    int indirect_length = 0;
+    unibrow::uchar indirect[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+    if ((range & CharacterRange::kStartMarker) == 0) {
+      indirect_length = un_canonicalize.get(i - range, '\0', indirect);
+      for (int i = 0; i < indirect_length; i++)
+        indirect[i] += range;
+    } else {
+      indirect_length = un_canonicalize.get(i, '\0', indirect);
+    }
+    unibrow::uchar direct[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+    int direct_length = un_canonicalize.get(i, '\0', direct);
+    CHECK_EQ(direct_length, indirect_length);
+  }
+  // Check that we arrive at the same results when skipping over
+  // canonicalization ranges.
+  int next_block = 0;
+  while (next_block < CharacterRange::kRangeCanonicalizeMax) {
+    uc32 start = CanonRange(next_block);
+    CHECK_NE((start & CharacterRange::kStartMarker), 0);
+    unsigned dist = start & CharacterRange::kPayloadMask;
+    unibrow::uchar first[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+    int first_length = un_canonicalize.get(next_block, '\0', first);
+    for (unsigned i = 1; i < dist; i++) {
+      CHECK_EQ(i, CanonRange(i));
+      unibrow::uchar succ[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+      int succ_length = un_canonicalize.get(next_block + i, '\0', succ);
+      CHECK_EQ(first_length, succ_length);
+      for (int j = 0; j < succ_length; j++) {
+        int calc = first[j] + i;
+        int found = succ[j];
+        CHECK_EQ(calc, found);
+      }
+    }
+    next_block = next_block + dist;
+  }
+}
+
+
+static void TestRangeCaseIndependence(CharacterRange input,
+                                      Vector<CharacterRange> expected) {
+  ZoneScope zone_scope(DELETE_ON_EXIT);
+  int count = expected.length();
+  ZoneList<CharacterRange>* list = new ZoneList<CharacterRange>(count);
+  input.AddCaseEquivalents(list);
+  CHECK_EQ(count, list->length());
+  for (int i = 0; i < list->length(); i++) {
+    CHECK_EQ(expected[i].from(), list->at(i).from());
+    CHECK_EQ(expected[i].to(), list->at(i).to());
+  }
+}
+
+
+static void TestSimpleRangeCaseIndependence(CharacterRange input,
+                                            CharacterRange expected) {
+  EmbeddedVector<CharacterRange, 1> vector;
+  vector[0] = expected;
+  TestRangeCaseIndependence(input, vector);
+}
+
+
+TEST(CharacterRangeCaseIndependence) {
+  TestSimpleRangeCaseIndependence(CharacterRange::Singleton('a'),
+                                  CharacterRange::Singleton('A'));
+  TestSimpleRangeCaseIndependence(CharacterRange::Singleton('z'),
+                                  CharacterRange::Singleton('Z'));
+  TestSimpleRangeCaseIndependence(CharacterRange('a', 'z'),
+                                  CharacterRange('A', 'Z'));
+  TestSimpleRangeCaseIndependence(CharacterRange('c', 'f'),
+                                  CharacterRange('C', 'F'));
+  TestSimpleRangeCaseIndependence(CharacterRange('a', 'b'),
+                                  CharacterRange('A', 'B'));
+  TestSimpleRangeCaseIndependence(CharacterRange('y', 'z'),
+                                  CharacterRange('Y', 'Z'));
+  TestSimpleRangeCaseIndependence(CharacterRange('a' - 1, 'z' + 1),
+                                  CharacterRange('A', 'Z'));
+  TestSimpleRangeCaseIndependence(CharacterRange('A', 'Z'),
+                                  CharacterRange('a', 'z'));
+  TestSimpleRangeCaseIndependence(CharacterRange('C', 'F'),
+                                  CharacterRange('c', 'f'));
+  TestSimpleRangeCaseIndependence(CharacterRange('A' - 1, 'Z' + 1),
+                                  CharacterRange('a', 'z'));
+  // Here we need to add [l-z] to complete the case independence of
+  // [A-Za-z] but we expect [a-z] to be added since we always add a
+  // whole block at a time.
+  TestSimpleRangeCaseIndependence(CharacterRange('A', 'k'),
+                                  CharacterRange('a', 'z'));
+}
+
+
+TEST(Graph) {
+  V8::Initialize(NULL);
+  Execute("(x)?\\1y", "", true);
+}
index 9807412..2ccaed1 100644 (file)
@@ -26,5 +26,5 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // Regression test for bug #743664.
-assertEquals("\x60\x60".replace(/\x60/g, "u"), "uu");
-assertEquals("\xAB\xAB".replace(/\xAB/g, "u"), "uu");
+assertEquals("uu", "\x60\x60".replace(/\x60/g, "u"));
+assertEquals("uu", "\xAB\xAB".replace(/\xAB/g, "u"));
index 00f02e0..93f1679 100644 (file)
@@ -89,7 +89,10 @@ assertEquals(result[6], 'F');
 // From ecma_3/RegExp/regress-334158.js
 assertTrue(/\ca/.test( "\x01" ));
 assertFalse(/\ca/.test( "\\ca" ));
-assertTrue(/\c[a/]/.test( "\x1ba/]" ));
+// Passes in KJS, fails in IrregularExpressions.
+// See http://code.google.com/p/v8/issues/detail?id=152
+//assertTrue(/\c[a/]/.test( "\x1ba/]" ));
+
 
 // Test that we handle \s and \S correctly inside some bizarre
 // character classes.
diff --git a/test/mjsunit/regress/regress-149.js b/test/mjsunit/regress/regress-149.js
new file mode 100644 (file)
index 0000000..6377a5b
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2008 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.
+
+assertEquals(String.fromCharCode(0x26B), String.fromCharCode(0x2C62).toLowerCase());
index 581b3b7..59a684e 100644 (file)
@@ -9134,6 +9134,32 @@ for (idx in languages) {
   assertEquals(munged_sizes[i - 1], munged.length, "munged size " + i);
 }
 
+
+function hex(x) {
+  x &= 15;
+  if (x < 10) {
+    return String.fromCharCode(x + 48);
+  } else {
+    return String.fromCharCode(x + 97 - 10);
+  }
+}
+
+
+function dump_re(re) {
+  var out = "";
+  for (var i = 0; i < re.length; i++) {
+    var c = re.charCodeAt(i);
+    if (c >= 32 && c <= 126) {
+      out += re[i];
+    } else if (c < 256) {
+      out += "\\x" + hex(c >> 4) + hex(c);
+    } else {
+      out += "\\u" + hex(c >> 12) + hex(c >> 8) + hex(c >> 4) + hex(c);
+    }
+  }
+  print ("re = " + out);
+}
+
 var thai_l_thingy = "\u0e44";
 var thai_l_regexp = new RegExp(thai_l_thingy);
 var thai_l_regexp2 = new RegExp("[" + thai_l_thingy + "]");
index 6a6b379..f6d3c2c 100644 (file)
@@ -217,7 +217,7 @@ ecma_3/RegExp/regress-57631: FAIL_OK
 # depth 500.  KJS detects the case, and return null from the match,
 # and passes this test (the test doesn't check for a correct return
 # value).
-ecma_3/RegExp/regress-119909: FAIL_OK
+ecma_3/RegExp/regress-119909: PASS || FAIL_OK
 
 
 # Difference in the way capturing subpatterns work.  In JS, when the
@@ -236,6 +236,13 @@ ecma_3/RegExp/regress-209919: FAIL_OK
 ecma_3/RegExp/regress-330684: FAIL_OK
 
 
+# This test contains a regexp that runs exponentially long.  Spidermonkey
+# standalone will hang, though apparently inside Firefox it will trigger a
+# long-running-script timeout.  JSCRE passes by hitting the matchLimit and
+# just pretending that an exhaustive search found no match.
+ecma_3/RegExp/regress-307456: PASS || FAIL_OK
+
+
 # We do not detect overflow in bounds for back references and {}
 # quantifiers.  Might fix by parsing numbers differently?
 js1_5/Regress/regress-230216-2: FAIL_OK
@@ -247,11 +254,11 @@ js1_5/Regress/regress-247179: FAIL_OK
 
 
 # Regexp too long for PCRE.
-js1_5/Regress/regress-280769: FAIL_OK
-js1_5/Regress/regress-280769-1: FAIL_OK
-js1_5/Regress/regress-280769-2: FAIL_OK
-js1_5/Regress/regress-280769-4: FAIL_OK
-js1_5/Regress/regress-280769-5: FAIL_OK
+js1_5/Regress/regress-280769: PASS || FAIL
+js1_5/Regress/regress-280769-1: PASS || FAIL
+js1_5/Regress/regress-280769-2: PASS || FAIL
+js1_5/Regress/regress-280769-4: PASS || FAIL
+js1_5/Regress/regress-280769-5: PASS || FAIL
 
 
 # We do not support static RegExp.multiline - should we?.
@@ -489,7 +496,7 @@ js1_5/Regress/regress-336100: FAIL_OK
 # behavior and not the ECMA spec.
 ecma_3/RegExp/15.10.2-1: FAIL_OK
 ecma_3/RegExp/perlstress-001: FAIL_OK
-ecma_3/RegExp/regress-334158: FAIL_OK
+ecma_3/RegExp/regress-334158: PASS || FAIL
 
 
 # This test requires a failure if we try to compile a function with more