ARM native regexps.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 31 Aug 2009 12:40:37 +0000 (12:40 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 31 Aug 2009 12:40:37 +0000 (12:40 +0000)
Review URL: http://codereview.chromium.org/173567

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

34 files changed:
SConstruct
src/SConscript
src/arm/assembler-arm-inl.h
src/arm/assembler-arm.cc
src/arm/assembler-arm.h
src/arm/codegen-arm.cc
src/arm/disasm-arm.cc
src/arm/regexp-macro-assembler-arm.cc
src/arm/regexp-macro-assembler-arm.h
src/arm/simulator-arm.cc
src/arm/simulator-arm.h
src/assembler.cc
src/assembler.h
src/code-stubs.h
src/globals.h
src/heap.cc
src/heap.h
src/ia32/regexp-macro-assembler-ia32.cc
src/ia32/regexp-macro-assembler-ia32.h
src/ia32/simulator-ia32.h
src/jsregexp.cc
src/regexp-macro-assembler-irregexp-inl.h
src/regexp-macro-assembler-irregexp.cc
src/regexp-macro-assembler-irregexp.h
src/regexp-macro-assembler-tracer.h
src/regexp-macro-assembler.cc
src/regexp-macro-assembler.h
src/serialize.cc
src/x64/regexp-macro-assembler-x64.cc
src/x64/regexp-macro-assembler-x64.h
src/x64/simulator-x64.h
test/cctest/test-assembler-arm.cc
test/cctest/test-regexp.cc
tools/gyp/v8.gyp

index 4d1792fd901470edd3c2be791636869e4d823e73..71673c0f0a2529371e9f4861235bc4d3b23fb245 100644 (file)
@@ -99,12 +99,7 @@ LIBRARY_FLAGS = {
     'CPPDEFINES':   ['ENABLE_LOGGING_AND_PROFILING'],
     'CPPPATH': [join(root_dir, 'src')],
     'regexp:native': {
-      'arch:ia32' : {
         'CPPDEFINES': ['V8_NATIVE_REGEXP']
-      },
-      'arch:x64' : {
-        'CPPDEFINES': ['V8_NATIVE_REGEXP']
-      }
     },
     'mode:debug': {
       'CPPDEFINES': ['V8_ENABLE_CHECKS']
index 6a38c1a79e2a0f25e638cd0bd2976a87ba68c1dc..fee3fab431ecf9008279728a242dc000b1aa8059 100755 (executable)
@@ -63,32 +63,22 @@ SOURCES = {
     'arm/register-allocator-arm.cc', 'arm/stub-cache-arm.cc',
     'arm/virtual-frame-arm.cc'
   ],
-  'arch:ia32': {
-    'all': [
-      'ia32/assembler-ia32.cc', 'ia32/builtins-ia32.cc', 'ia32/cfg-ia32.cc',
-      'ia32/codegen-ia32.cc', 'ia32/cpu-ia32.cc', 'ia32/disasm-ia32.cc',
-      'ia32/debug-ia32.cc', 'ia32/frames-ia32.cc', 'ia32/ic-ia32.cc',
-      'ia32/jump-target-ia32.cc', 'ia32/macro-assembler-ia32.cc',
-      'ia32/register-allocator-ia32.cc', 'ia32/stub-cache-ia32.cc',
-      'ia32/virtual-frame-ia32.cc'
-    ],
-    'regexp:native': [
-      'ia32/regexp-macro-assembler-ia32.cc',
-    ]
-  },
-  'arch:x64': {
-    'all': [
-      'x64/assembler-x64.cc', 'x64/builtins-x64.cc', 'x64/cfg-x64.cc',
-      'x64/codegen-x64.cc', 'x64/cpu-x64.cc', 'x64/disasm-x64.cc',
-      'x64/debug-x64.cc', 'x64/frames-x64.cc', 'x64/ic-x64.cc',
-      'x64/jump-target-x64.cc', 'x64/macro-assembler-x64.cc',
-      'x64/register-allocator-x64.cc',
-      'x64/stub-cache-x64.cc', 'x64/virtual-frame-x64.cc'
-    ],
-    'regexp:native': [
-      'x64/regexp-macro-assembler-x64.cc'
-    ]
-  },
+  'arch:ia32': [
+    'ia32/assembler-ia32.cc', 'ia32/builtins-ia32.cc', 'ia32/cfg-ia32.cc',
+    'ia32/codegen-ia32.cc', 'ia32/cpu-ia32.cc', 'ia32/disasm-ia32.cc',
+    'ia32/debug-ia32.cc', 'ia32/frames-ia32.cc', 'ia32/ic-ia32.cc',
+    'ia32/jump-target-ia32.cc', 'ia32/macro-assembler-ia32.cc',
+    'ia32/regexp-macro-assembler-ia32.cc', 'ia32/register-allocator-ia32.cc',
+    'ia32/stub-cache-ia32.cc', 'ia32/virtual-frame-ia32.cc'
+  ],
+  'arch:x64': [
+    'x64/assembler-x64.cc', 'x64/builtins-x64.cc', 'x64/cfg-x64.cc',
+    'x64/codegen-x64.cc', 'x64/cpu-x64.cc', 'x64/disasm-x64.cc',
+    'x64/debug-x64.cc', 'x64/frames-x64.cc', 'x64/ic-x64.cc',
+    'x64/jump-target-x64.cc', 'x64/macro-assembler-x64.cc',
+    'x64/regexp-macro-assembler-x64.cc', 'x64/register-allocator-x64.cc',
+    'x64/stub-cache-x64.cc', 'x64/virtual-frame-x64.cc'
+  ],
   'simulator:arm': ['arm/simulator-arm.cc'],
   'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'],
   'os:linux':   ['platform-linux.cc', 'platform-posix.cc'],
index 4dda7ec5b5778e6f657911f4de19ac36df1a0ae0..cb5faa23475b7f90527e167b84e30d42211efff5 100644 (file)
@@ -204,7 +204,7 @@ void Assembler::CheckBuffer() {
   if (buffer_space() <= kGap) {
     GrowBuffer();
   }
-  if (pc_offset() > next_buffer_check_) {
+  if (pc_offset() >= next_buffer_check_) {
     CheckConstPool(false, true);
   }
 }
index 3ed99f9e1590171fed8f1fc17bf21d637de4ed83..8bd06dbfed0976f6fb8b5b6955f9bc2523aedb68 100644 (file)
@@ -329,19 +329,30 @@ const int kEndOfChain = -4;
 
 int Assembler::target_at(int pos)  {
   Instr instr = instr_at(pos);
+  if ((instr & ~Imm24Mask) == 0) {
+    // Emitted label constant, not part of a branch.
+    return instr - (Code::kHeaderSize - kHeapObjectTag);
+  }
   ASSERT((instr & 7*B25) == 5*B25);  // b, bl, or blx imm24
   int imm26 = ((instr & Imm24Mask) << 8) >> 6;
   if ((instr & CondMask) == nv && (instr & B24) != 0)
     // blx uses bit 24 to encode bit 2 of imm26
     imm26 += 2;
 
-  return pos + 8 + imm26;
+  return pos + kPcLoadDelta + imm26;
 }
 
 
 void Assembler::target_at_put(int pos, int target_pos) {
-  int imm26 = target_pos - pos - 8;
   Instr instr = instr_at(pos);
+  if ((instr & ~Imm24Mask) == 0) {
+    ASSERT(target_pos == kEndOfChain || target_pos >= 0);
+    // Emitted label constant, not part of a branch.
+    // Make label relative to Code* of generated Code object.
+    instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
+    return;
+  }
+  int imm26 = target_pos - (pos + kPcLoadDelta);
   ASSERT((instr & 7*B25) == 5*B25);  // b, bl, or blx imm24
   if ((instr & CondMask) == nv) {
     // blx uses bit 24 to encode bit 2 of imm26
@@ -368,41 +379,45 @@ void Assembler::print(Label* L) {
     while (l.is_linked()) {
       PrintF("@ %d ", l.pos());
       Instr instr = instr_at(l.pos());
-      ASSERT((instr & 7*B25) == 5*B25);  // b, bl, or blx
-      int cond = instr & CondMask;
-      const char* b;
-      const char* c;
-      if (cond == nv) {
-        b = "blx";
-        c = "";
+      if ((instr & ~Imm24Mask) == 0) {
+        PrintF("value\n");
       } else {
-        if ((instr & B24) != 0)
-          b = "bl";
-        else
-          b = "b";
-
-        switch (cond) {
-          case eq: c = "eq"; break;
-          case ne: c = "ne"; break;
-          case hs: c = "hs"; break;
-          case lo: c = "lo"; break;
-          case mi: c = "mi"; break;
-          case pl: c = "pl"; break;
-          case vs: c = "vs"; break;
-          case vc: c = "vc"; break;
-          case hi: c = "hi"; break;
-          case ls: c = "ls"; break;
-          case ge: c = "ge"; break;
-          case lt: c = "lt"; break;
-          case gt: c = "gt"; break;
-          case le: c = "le"; break;
-          case al: c = ""; break;
-          default:
-            c = "";
-            UNREACHABLE();
+        ASSERT((instr & 7*B25) == 5*B25);  // b, bl, or blx
+        int cond = instr & CondMask;
+        const char* b;
+        const char* c;
+        if (cond == nv) {
+          b = "blx";
+          c = "";
+        } else {
+          if ((instr & B24) != 0)
+            b = "bl";
+          else
+            b = "b";
+
+          switch (cond) {
+            case eq: c = "eq"; break;
+            case ne: c = "ne"; break;
+            case hs: c = "hs"; break;
+            case lo: c = "lo"; break;
+            case mi: c = "mi"; break;
+            case pl: c = "pl"; break;
+            case vs: c = "vs"; break;
+            case vc: c = "vc"; break;
+            case hi: c = "hi"; break;
+            case ls: c = "ls"; break;
+            case ge: c = "ge"; break;
+            case lt: c = "lt"; break;
+            case gt: c = "gt"; break;
+            case le: c = "le"; break;
+            case al: c = ""; break;
+            default:
+              c = "";
+              UNREACHABLE();
+          }
         }
+        PrintF("%s%s\n", b, c);
       }
-      PrintF("%s%s\n", b, c);
       next(&l);
     }
   } else {
@@ -670,8 +685,23 @@ int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
   // Block the emission of the constant pool, since the branch instruction must
   // be emitted at the pc offset recorded by the label
   BlockConstPoolBefore(pc_offset() + kInstrSize);
+  return target_pos - (pc_offset() + kPcLoadDelta);
+}
 
-  return target_pos - pc_offset() - 8;
+
+void Assembler::label_at_put(Label* L, int at_offset) {
+  int target_pos;
+  if (L->is_bound()) {
+    target_pos = L->pos();
+  } else {
+    if (L->is_linked()) {
+      target_pos = L->pos();  // L's link
+    } else {
+      target_pos = kEndOfChain;
+    }
+    L->link_to(at_offset);
+    instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
+  }
 }
 
 
index b3ebb8be8b8369c3b387acbe6f28ef5b87d22cff..63f04473e16419e7ee752cf33b030a40ce24a682 100644 (file)
@@ -39,7 +39,7 @@
 
 #ifndef V8_ARM_ASSEMBLER_ARM_H_
 #define V8_ARM_ASSEMBLER_ARM_H_
-
+#include <stdio.h>
 #include "assembler.h"
 
 namespace v8 {
@@ -165,9 +165,10 @@ enum Coprocessor {
 enum Condition {
   eq =  0 << 28,  // Z set            equal.
   ne =  1 << 28,  // Z clear          not equal.
-  cs =  2 << 28,  // C set            unsigned higher or same.
+  nz =  1 << 28,  // Z clear          not zero.
+  cs =  2 << 28,  // C set            carry set.
   hs =  2 << 28,  // C set            unsigned higher or same.
-  cc =  3 << 28,  // C clear          unsigned lower.
+  cc =  3 << 28,  // C clear          carry clear.
   lo =  3 << 28,  // C clear          unsigned lower.
   mi =  4 << 28,  // N set            negative.
   pl =  5 << 28,  // N clear          positive or zero.
@@ -420,6 +421,10 @@ class Assembler : public Malloced {
   // Manages the jump elimination optimization if the second parameter is true.
   int branch_offset(Label* L, bool jump_elimination_allowed);
 
+  // Puts a labels target address at the given position.
+  // The high 8 bits are set to zero.
+  void label_at_put(Label* L, int at_offset);
+
   // Return the address in the constant pool of the code target address used by
   // the branch/call instruction at pc.
   INLINE(static Address target_address_address_at(Address pc));
@@ -435,6 +440,10 @@ class Assembler : public Malloced {
   // to jump to.
   static const int kPatchReturnSequenceAddressOffset = 1;
 
+  // Difference between address of current opcode and value read from pc
+  // register.
+  static const int kPcLoadDelta = 8;
+
 
   // ---------------------------------------------------------------------------
   // Code generation
@@ -784,6 +793,8 @@ class Assembler : public Malloced {
 
   // Record reloc info for current pc_
   void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
+
+  friend class RegExpMacroAssemblerARM;
 };
 
 } }  // namespace v8::internal
index ff8711a613db67f8af381e5f92c62f32fabc8b67..880507d0626d58753e5ec518f9d6e1bc41d2687a 100644 (file)
@@ -5682,9 +5682,9 @@ void UnarySubStub::Generate(MacroAssembler* masm) {
     __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
   } else {
     AllocateHeapNumber(masm, &slow, r1, r2, r3);
-    __ ldr(r2, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
-    __ str(r2, FieldMemOperand(r1, HeapNumber::kMantissaOffset));
+    __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
     __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
+    __ str(r3, FieldMemOperand(r1, HeapNumber::kMantissaOffset));
     __ eor(r2, r2, Operand(HeapNumber::kSignMask));  // Flip sign.
     __ str(r2, FieldMemOperand(r1, HeapNumber::kExponentOffset));
     __ mov(r0, Operand(r1));
index 0abe35b9e22253f8906e4c3d91fa248aa5b4d2cf..2638409e853569fa72de0f6367b65461a69b69f1 100644 (file)
@@ -119,6 +119,7 @@ class Decoder {
   void DecodeType5(Instr* instr);
   void DecodeType6(Instr* instr);
   void DecodeType7(Instr* instr);
+  void DecodeUnconditional(Instr* instr);
 
   const disasm::NameConverter& converter_;
   v8::internal::Vector<char> out_buffer_;
@@ -774,6 +775,67 @@ void Decoder::DecodeType7(Instr* instr) {
 }
 
 
+void Decoder::DecodeUnconditional(Instr* instr) {
+  if (instr->Bits(7, 4) == 0xB && instr->Bits(27, 25) == 0 && instr->HasL()) {
+    Format(instr, "'memop'h'pu 'rd, ");
+    bool immediate = instr->HasB();
+    switch (instr->PUField()) {
+      case 0: {
+        // Post index, negative.
+        if (instr->HasW()) {
+          Unknown(instr);
+          break;
+        }
+        if (immediate) {
+          Format(instr, "['rn], #-'imm12");
+        } else {
+          Format(instr, "['rn], -'rm");
+        }
+        break;
+      }
+      case 1: {
+        // Post index, positive.
+        if (instr->HasW()) {
+          Unknown(instr);
+          break;
+        }
+        if (immediate) {
+          Format(instr, "['rn], #+'imm12");
+        } else {
+          Format(instr, "['rn], +'rm");
+        }
+        break;
+      }
+      case 2: {
+        // Pre index or offset, negative.
+        if (immediate) {
+          Format(instr, "['rn, #-'imm12]'w");
+        } else {
+          Format(instr, "['rn, -'rm]'w");
+        }
+        break;
+      }
+      case 3: {
+        // Pre index or offset, positive.
+        if (immediate) {
+          Format(instr, "['rn, #+'imm12]'w");
+        } else {
+          Format(instr, "['rn, +'rm]'w");
+        }
+        break;
+      }
+      default: {
+        // The PU field is a 2-bit field.
+        UNREACHABLE();
+        break;
+      }
+    }
+    return;
+  }
+  Format(instr, "break 'msg");
+}
+
+
 // Disassemble the instruction at *instr_ptr into the output buffer.
 int Decoder::InstructionDecode(byte* instr_ptr) {
   Instr* instr = Instr::At(instr_ptr);
@@ -782,7 +844,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) {
                                        "%08x       ",
                                        instr->InstructionBits());
   if (instr->ConditionField() == special_condition) {
-    Format(instr, "break 'msg");
+    DecodeUnconditional(instr);
     return Instr::kInstrSize;
   }
   switch (instr->TypeField()) {
index 78ebc7e8011f1bce77ddb193a3ba78e06373f88d..63f47f67edea620db9bdfe4d40c93a3d3190453d 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2009 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:
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "v8.h"
+#include "unicode.h"
+#include "log.h"
 #include "ast.h"
+#include "regexp-stack.h"
+#include "macro-assembler.h"
 #include "regexp-macro-assembler.h"
+#include "arm/macro-assembler-arm.h"
 #include "arm/regexp-macro-assembler-arm.h"
 
 namespace v8 {
 namespace internal {
 
-RegExpMacroAssemblerARM::RegExpMacroAssemblerARM() {
-  UNIMPLEMENTED();
+#ifdef V8_NATIVE_REGEXP
+/*
+ * This assembler uses the following register assignment convention
+ * - r5 : Pointer to current code object (Code*) including heap object tag.
+ * - r6 : Current position in input, as negative offset from end of string.
+ *        Please notice that this is the byte offset, not the character offset!
+ * - r7 : Currently loaded character. Must be loaded using
+ *        LoadCurrentCharacter before using any of the dispatch methods.
+ * - r8 : points to tip of backtrack stack
+ * - r9 : Unused, might be used by C code and expected unchanged.
+ * - r10 : End of input (points to byte after last character in input).
+ * - r11 : Frame pointer. Used to access arguments, local variables and
+ *         RegExp registers.
+ * - r12 : IP register, used by assembler. Very volatile.
+ * - r13/sp : points to tip of C stack.
+ *
+ * The remaining registers are free for computations.
+ *
+ * Each call to a public method should retain this convention.
+ * The stack will have the following structure:
+ *       - stack_area_base    (High end of the memory area to use as
+ *                             backtracking stack)
+ *       - at_start           (if 1, start at start of string, if 0, don't)
+ *       --- sp when called ---
+ *       - link address
+ *       - backup of registers r4..r11
+ *       - int* capture_array (int[num_saved_registers_], for output).
+ *       - end of input       (Address of end of string)
+ *       - start of input     (Address of first character in string)
+ *       --- frame pointer ----
+ *       - void* input_string (location of a handle containing the string)
+ *       - Offset of location before start of input (effectively character
+ *         position -1). Used to initialize capture registers to a non-position.
+ *       - register 0         (Only positions must be stored in the first
+ *       - register 1          num_saved_registers_ registers)
+ *       - ...
+ *       - register num_registers-1
+ *       --- sp ---
+ *
+ * The first num_saved_registers_ registers are initialized to point to
+ * "character -1" in the string (i.e., char_size() bytes before the first
+ * character of the string). The remaining registers start out as garbage.
+ *
+ * The data up to the return address must be placed there by the calling
+ * code, by calling the code entry as cast to a function with the signature:
+ * int (*match)(String* input_string,
+ *              Address start,
+ *              Address end,
+ *              int* capture_output_array,
+ *              bool at_start,
+ *              byte* stack_area_base)
+ * The call is performed by NativeRegExpMacroAssembler::Execute()
+ * (in regexp-macro-assembler.cc).
+ */
+
+#define __ ACCESS_MASM(masm_)
+
+RegExpMacroAssemblerARM::RegExpMacroAssemblerARM(
+    Mode mode,
+    int registers_to_save)
+    : masm_(new MacroAssembler(NULL, kRegExpCodeSize)),
+      mode_(mode),
+      num_registers_(registers_to_save),
+      num_saved_registers_(registers_to_save),
+      entry_label_(),
+      start_label_(),
+      success_label_(),
+      backtrack_label_(),
+      exit_label_() {
+  ASSERT_EQ(0, registers_to_save % 2);
+  __ jmp(&entry_label_);   // We'll write the entry code later.
+  EmitBacktrackConstantPool();
+  __ bind(&start_label_);  // And then continue from here.
 }
 
 
-RegExpMacroAssemblerARM::~RegExpMacroAssemblerARM() {}
+RegExpMacroAssemblerARM::~RegExpMacroAssemblerARM() {
+  delete masm_;
+  // Unuse labels in case we throw away the assembler without calling GetCode.
+  entry_label_.Unuse();
+  start_label_.Unuse();
+  success_label_.Unuse();
+  backtrack_label_.Unuse();
+  exit_label_.Unuse();
+  check_preempt_label_.Unuse();
+  stack_overflow_label_.Unuse();
+}
 
-}}  // namespace v8::internal
 
+int RegExpMacroAssemblerARM::stack_limit_slack()  {
+  return RegExpStack::kStackLimitSlack;
+}
+
+
+bool RegExpMacroAssemblerARM::CanReadUnaligned() {
+#if V8_TARGET_CAN_READ_UNALIGNED
+  return true;
+#else
+  return false;
+#endif
+}
+
+
+void RegExpMacroAssemblerARM::AdvanceCurrentPosition(int by) {
+  if (by != 0) {
+    Label inside_string;
+    __ add(current_input_offset(),
+           current_input_offset(), Operand(by * char_size()));
+  }
+}
+
+
+void RegExpMacroAssemblerARM::AdvanceRegister(int reg, int by) {
+  ASSERT(reg >= 0);
+  ASSERT(reg < num_registers_);
+  if (by != 0) {
+    __ ldr(r0, register_location(reg));
+    __ add(r0, r0, Operand(by));
+    __ str(r0, register_location(reg));
+  }
+}
+
+
+void RegExpMacroAssemblerARM::Backtrack() {
+  CheckPreemption();
+  // Pop Code* offset from backtrack stack, add Code* and jump to location.
+  Pop(r0);
+  __ add(pc, r0, Operand(r5));
+}
+
+
+void RegExpMacroAssemblerARM::Bind(Label* label) {
+  __ bind(label);
+}
+
+
+void RegExpMacroAssemblerARM::CheckCharacter(uint32_t c, Label* on_equal) {
+  __ cmp(current_character(), Operand(c));
+  BranchOrBacktrack(eq, on_equal);
+}
+
+
+void RegExpMacroAssemblerARM::CheckCharacterGT(uc16 limit, Label* on_greater) {
+  __ cmp(current_character(), Operand(limit));
+  BranchOrBacktrack(gt, on_greater);
+}
+
+
+void RegExpMacroAssemblerARM::CheckAtStart(Label* on_at_start) {
+  Label not_at_start;
+  // Did we start the match at the start of the string at all?
+  __ ldr(r0, MemOperand(frame_pointer(), kAtStart));
+  __ cmp(r0, Operand(0));
+  BranchOrBacktrack(eq, &not_at_start);
+
+  // If we did, are we still at the start of the input?
+  __ ldr(r1, MemOperand(frame_pointer(), kInputStart));
+  __ add(r0, end_of_input_address(), Operand(current_input_offset()));
+  __ cmp(r0, r1);
+  BranchOrBacktrack(eq, on_at_start);
+  __ bind(&not_at_start);
+}
+
+
+void RegExpMacroAssemblerARM::CheckNotAtStart(Label* on_not_at_start) {
+  // Did we start the match at the start of the string at all?
+  __ ldr(r0, MemOperand(frame_pointer(), kAtStart));
+  __ cmp(r0, Operand(0));
+  BranchOrBacktrack(eq, on_not_at_start);
+  // If we did, are we still at the start of the input?
+  __ ldr(r1, MemOperand(frame_pointer(), kInputStart));
+  __ add(r0, end_of_input_address(), Operand(current_input_offset()));
+  __ cmp(r0, r1);
+  BranchOrBacktrack(ne, on_not_at_start);
+}
+
+
+void RegExpMacroAssemblerARM::CheckCharacterLT(uc16 limit, Label* on_less) {
+  __ cmp(current_character(), Operand(limit));
+  BranchOrBacktrack(lt, on_less);
+}
+
+
+void RegExpMacroAssemblerARM::CheckCharacters(Vector<const uc16> str,
+                                              int cp_offset,
+                                              Label* on_failure,
+                                              bool check_end_of_string) {
+  int byte_length = str.length() * char_size();
+  int byte_offset = cp_offset * char_size();
+  if (check_end_of_string) {
+    // Check that there are at least str.length() characters left in the input.
+    __ cmp(end_of_input_address(), Operand(-(byte_offset + byte_length)));
+    BranchOrBacktrack(gt, on_failure);
+  }
+
+  if (on_failure == NULL) {
+    // Instead of inlining a backtrack, (re)use the global backtrack target.
+    on_failure = &backtrack_label_;
+  }
+
+  __ add(r0, end_of_input_address(), Operand(current_input_offset()));
+  int stored_high_byte = 0;
+  for (int i = 0; i < str.length(); i++) {
+    if (mode_ == ASCII) {
+      __ ldrb(r1, MemOperand(r0, char_size(), PostIndex));
+      // str[i] is known to be an ASCII character.
+      __ cmp(r1, Operand(str[i]));
+    } else {
+      __ ldrh(r1, MemOperand(r0, char_size(), PostIndex));
+      uc16 match_char = str[i];
+      int match_high_byte = (match_char >> 8);
+      if (match_high_byte == 0) {
+        __ cmp(r1, Operand(str[i]));
+      } else {
+        if (match_high_byte != stored_high_byte) {
+          __ mov(r2, Operand(match_high_byte));
+          stored_high_byte = match_high_byte;
+        }
+        __ add(r3, r2, Operand(match_char & 0xff));
+        __ cmp(r1, r3);
+      }
+    }
+    BranchOrBacktrack(ne, on_failure);
+  }
+}
+
+
+void RegExpMacroAssemblerARM::CheckGreedyLoop(Label* on_equal) {
+  __ ldr(r0, MemOperand(backtrack_stackpointer(), 0));
+  __ cmp(current_input_offset(), r0);
+  __ add(backtrack_stackpointer(),
+         backtrack_stackpointer(), Operand(kPointerSize), LeaveCC, eq);
+  BranchOrBacktrack(eq, on_equal);
+}
+
+
+void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase(
+    int start_reg,
+    Label* on_no_match) {
+  Label fallthrough;
+  __ ldr(r0, register_location(start_reg));  // Index of start of capture
+  __ ldr(r1, register_location(start_reg + 1));  // Index of end of capture
+  __ sub(r1, r1, r0, SetCC);  // Length of capture.
+
+  // If length is zero, either the capture is empty or it is not participating.
+  // In either case succeed immediately.
+  __ b(eq, &fallthrough);
+
+  // Check that there are enough characters left in the input.
+  __ cmn(r1, Operand(current_input_offset()));
+  BranchOrBacktrack(gt, on_no_match);
+
+  if (mode_ == ASCII) {
+    Label success;
+    Label fail;
+    Label loop_check;
+
+    // r0 - offset of start of capture
+    // r1 - length of capture
+    __ add(r0, r0, Operand(end_of_input_address()));
+    __ add(r2, end_of_input_address(), Operand(current_input_offset()));
+    __ add(r1, r0, Operand(r1));
+
+    // r0 - Address of start of capture.
+    // r1 - Address of end of capture
+    // r2 - Address of current input position.
+
+    Label loop;
+    __ bind(&loop);
+    __ ldrb(r3, MemOperand(r0, char_size(), PostIndex));
+    __ ldrb(r4, MemOperand(r2, char_size(), PostIndex));
+    __ cmp(r4, r3);
+    __ b(eq, &loop_check);
+
+    // Mismatch, try case-insensitive match (converting letters to lower-case).
+    __ orr(r3, r3, Operand(0x20));  // Convert capture character to lower-case.
+    __ orr(r4, r4, Operand(0x20));  // Also convert input character.
+    __ cmp(r4, r3);
+    __ b(ne, &fail);
+    __ sub(r3, r3, Operand('a'));
+    __ cmp(r3, Operand('z' - 'a'));  // Is r3 a lowercase letter?
+    __ b(hi, &fail);
+
+
+    __ bind(&loop_check);
+    __ cmp(r0, r1);
+    __ b(lt, &loop);
+    __ jmp(&success);
+
+    __ bind(&fail);
+    BranchOrBacktrack(al, on_no_match);
+
+    __ bind(&success);
+    // Compute new value of character position after the matched part.
+    __ sub(current_input_offset(), r2, end_of_input_address());
+  } else {
+    ASSERT(mode_ == UC16);
+    int argument_count = 3;
+    FrameAlign(argument_count, r2);
+
+    // r0 - offset of start of capture
+    // r1 - length of capture
+
+    // Put arguments into arguments registers.
+    // Parameters are
+    //   r0: Address byte_offset1 - Address captured substring's start.
+    //   r1: Address byte_offset2 - Address of current character position.
+    //   r2: size_t byte_length - length of capture in bytes(!)
+
+    // Address of start of capture.
+    __ add(r0, r0, Operand(end_of_input_address()));
+    // Length of capture.
+    __ mov(r2, Operand(r1));
+    // Save length in callee-save register for use on return.
+    __ mov(r4, Operand(r1));
+    // Address of current input position.
+    __ add(r1, current_input_offset(), Operand(end_of_input_address()));
+
+    ExternalReference function =
+        ExternalReference::re_case_insensitive_compare_uc16();
+    CallCFunction(function, argument_count);
+
+    // Check if function returned non-zero for success or zero for failure.
+    __ cmp(r0, Operand(0));
+    BranchOrBacktrack(eq, on_no_match);
+    // On success, increment position by length of capture.
+    __ add(current_input_offset(), current_input_offset(), Operand(r4));
+  }
+
+  __ bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerARM::CheckNotBackReference(
+    int start_reg,
+    Label* on_no_match) {
+  Label fallthrough;
+  Label success;
+
+  // Find length of back-referenced capture.
+  __ ldr(r0, register_location(start_reg));
+  __ ldr(r1, register_location(start_reg + 1));
+  __ sub(r1, r1, r0, SetCC);  // Length to check.
+  // Succeed on empty capture (including no capture).
+  __ b(eq, &fallthrough);
+
+  // Check that there are enough characters left in the input.
+  __ cmn(r1, Operand(current_input_offset()));
+  BranchOrBacktrack(gt, on_no_match);
+
+  // Compute pointers to match string and capture string
+  __ add(r0, r0, Operand(end_of_input_address()));
+  __ add(r2, end_of_input_address(), Operand(current_input_offset()));
+  __ add(r1, r1, Operand(r0));
+
+  Label loop;
+  __ bind(&loop);
+  if (mode_ == ASCII) {
+    __ ldrb(r3, MemOperand(r0, char_size(), PostIndex));
+    __ ldrb(r4, MemOperand(r2, char_size(), PostIndex));
+  } else {
+    ASSERT(mode_ == UC16);
+    __ ldrh(r3, MemOperand(r0, char_size(), PostIndex));
+    __ ldrh(r4, MemOperand(r2, char_size(), PostIndex));
+  }
+  __ cmp(r3, r4);
+  BranchOrBacktrack(ne, on_no_match);
+  __ cmp(r0, r1);
+  __ b(lt, &loop);
+
+  // Move current character position to position after match.
+  __ sub(current_input_offset(), r2, end_of_input_address());
+  __ bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerARM::CheckNotRegistersEqual(int reg1,
+                                                      int reg2,
+                                                      Label* on_not_equal) {
+  __ ldr(r0, register_location(reg1));
+  __ ldr(r1, register_location(reg2));
+  __ cmp(r0, r1);
+  BranchOrBacktrack(ne, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerARM::CheckNotCharacter(uint32_t c,
+                                                Label* on_not_equal) {
+  __ cmp(current_character(), Operand(c));
+  BranchOrBacktrack(ne, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerARM::CheckCharacterAfterAnd(uint32_t c,
+                                                     uint32_t mask,
+                                                     Label* on_equal) {
+  __ and_(r0, current_character(), Operand(mask));
+  __ cmp(r0, Operand(c));
+  BranchOrBacktrack(eq, on_equal);
+}
+
+
+void RegExpMacroAssemblerARM::CheckNotCharacterAfterAnd(uint32_t c,
+                                                        uint32_t mask,
+                                                        Label* on_not_equal) {
+  __ and_(r0, current_character(), Operand(mask));
+  __ cmp(r0, Operand(c));
+  BranchOrBacktrack(ne, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerARM::CheckNotCharacterAfterMinusAnd(
+    uc16 c,
+    uc16 minus,
+    uc16 mask,
+    Label* on_not_equal) {
+  ASSERT(minus < String::kMaxUC16CharCode);
+  __ sub(r0, current_character(), Operand(minus));
+  __ and_(r0, r0, Operand(mask));
+  __ cmp(r0, Operand(c));
+  BranchOrBacktrack(ne, on_not_equal);
+}
+
+
+bool RegExpMacroAssemblerARM::CheckSpecialCharacterClass(uc16 type,
+                                                         int cp_offset,
+                                                         bool check_offset,
+                                                         Label* on_no_match) {
+  // Range checks (c in min..max) are generally implemented by an unsigned
+  // (c - min) <= (max - min) check
+  switch (type) {
+  case 's':
+    // Match space-characters
+    if (mode_ == ASCII) {
+      // ASCII space characters are '\t'..'\r' and ' '.
+      if (check_offset) {
+        LoadCurrentCharacter(cp_offset, on_no_match);
+      } else {
+        LoadCurrentCharacterUnchecked(cp_offset, 1);
+      }
+      Label success;
+      __ cmp(current_character(), Operand(' '));
+      __ b(eq, &success);
+      // Check range 0x09..0x0d
+      __ sub(r0, current_character(), Operand('\t'));
+      __ cmp(r0, Operand('\r' - '\t'));
+      BranchOrBacktrack(hi, on_no_match);
+      __ bind(&success);
+      return true;
+    }
+    return false;
+  case 'S':
+    // Match non-space characters.
+    if (check_offset) {
+      LoadCurrentCharacter(cp_offset, on_no_match, 1);
+    } else {
+      LoadCurrentCharacterUnchecked(cp_offset, 1);
+    }
+    if (mode_ == ASCII) {
+      // ASCII space characters are '\t'..'\r' and ' '.
+      __ cmp(current_character(), Operand(' '));
+      BranchOrBacktrack(eq, on_no_match);
+      __ sub(r0, current_character(), Operand('\t'));
+      __ cmp(r0, Operand('\r' - '\t'));
+      BranchOrBacktrack(ls, on_no_match);
+      return true;
+    }
+    return false;
+  case 'd':
+    // Match ASCII digits ('0'..'9')
+    if (check_offset) {
+      LoadCurrentCharacter(cp_offset, on_no_match, 1);
+    } else {
+      LoadCurrentCharacterUnchecked(cp_offset, 1);
+    }
+    __ sub(r0, current_character(), Operand('0'));
+    __ cmp(current_character(), Operand('9' - '0'));
+    BranchOrBacktrack(hi, on_no_match);
+    return true;
+  case 'D':
+    // Match non ASCII-digits
+    if (check_offset) {
+      LoadCurrentCharacter(cp_offset, on_no_match, 1);
+    } else {
+      LoadCurrentCharacterUnchecked(cp_offset, 1);
+    }
+    __ sub(r0, current_character(), Operand('0'));
+    __ cmp(r0, Operand('9' - '0'));
+    BranchOrBacktrack(ls, on_no_match);
+    return true;
+  case '.': {
+    // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
+    if (check_offset) {
+      LoadCurrentCharacter(cp_offset, on_no_match, 1);
+    } else {
+      LoadCurrentCharacterUnchecked(cp_offset, 1);
+    }
+    __ eor(r0, current_character(), Operand(0x01));
+    // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
+    __ sub(r0, r0, Operand(0x0b));
+    __ cmp(r0, Operand(0x0c - 0x0b));
+    BranchOrBacktrack(ls, on_no_match);
+    if (mode_ == UC16) {
+      // Compare original value to 0x2028 and 0x2029, using the already
+      // computed (current_char ^ 0x01 - 0x0b). I.e., check for
+      // 0x201d (0x2028 - 0x0b) or 0x201e.
+      __ sub(r0, r0, Operand(0x2028 - 0x0b));
+      __ cmp(r0, Operand(1));
+      BranchOrBacktrack(ls, on_no_match);
+    }
+    return true;
+  }
+  case '*':
+    // Match any character.
+    if (check_offset) {
+      CheckPosition(cp_offset, on_no_match);
+    }
+    return true;
+  // No custom implementation (yet): w, W, s(UC16), S(UC16).
+  default:
+    return false;
+  }
+}
+
+
+void RegExpMacroAssemblerARM::Fail() {
+  __ mov(r0, Operand(FAILURE));
+  __ jmp(&exit_label_);
+}
+
+
+Handle<Object> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
+  // Finalize code - write the entry point code now we know how many
+  // registers we need.
+
+  // Entry code:
+  __ bind(&entry_label_);
+  // Push Link register.
+  // Push arguments
+  // Save callee-save registers.
+  // Start new stack frame.
+  // Order here should correspond to order of offset constants in header file.
+  RegList registers_to_retain = r4.bit() | r5.bit() | r6.bit() |
+      r7.bit() | r8.bit() | r9.bit() | r10.bit() | fp.bit();
+  RegList argument_registers = r0.bit() | r1.bit() | r2.bit() | r3.bit();
+  __ stm(db_w, sp, argument_registers | registers_to_retain | lr.bit());
+  // Set frame pointer just above the arguments.
+  __ add(frame_pointer(), sp, Operand(4 * kPointerSize));
+  __ push(r0);  // Make room for "position - 1" constant (value is irrelevant).
+
+  // Check if we have space on the stack for registers.
+  Label stack_limit_hit;
+  Label stack_ok;
+
+  ExternalReference stack_guard_limit =
+      ExternalReference::address_of_stack_guard_limit();
+  __ mov(r0, Operand(stack_guard_limit));
+  __ ldr(r0, MemOperand(r0));
+  __ sub(r0, sp, r0, SetCC);
+  // Handle it if the stack pointer is already below the stack limit.
+  __ b(ls, &stack_limit_hit);
+  // Check if there is room for the variable number of registers above
+  // the stack limit.
+  __ cmp(r0, Operand(num_registers_ * kPointerSize));
+  __ b(hs, &stack_ok);
+  // Exit with OutOfMemory exception. There is not enough space on the stack
+  // for our working registers.
+  __ mov(r0, Operand(EXCEPTION));
+  __ jmp(&exit_label_);
+
+  __ bind(&stack_limit_hit);
+  CallCheckStackGuardState(r0);
+  __ cmp(r0, Operand(0));
+  // If returned value is non-zero, we exit with the returned value as result.
+  __ b(ne, &exit_label_);
+
+  __ bind(&stack_ok);
+
+  // Allocate space on stack for registers.
+  __ sub(sp, sp, Operand(num_registers_ * kPointerSize));
+  // Load string end.
+  __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
+  // Load input start.
+  __ ldr(r0, MemOperand(frame_pointer(), kInputStart));
+  // Find negative length (offset of start relative to end).
+  __ sub(current_input_offset(), r0, end_of_input_address());
+  // Set r0 to address of char before start of input
+  // (effectively string position -1).
+  __ sub(r0, current_input_offset(), Operand(char_size()));
+  // Store this value in a local variable, for use when clearing
+  // position registers.
+  __ str(r0, MemOperand(frame_pointer(), kInputStartMinusOne));
+  if (num_saved_registers_ > 0) {  // Always is, if generated from a regexp.
+    // Fill saved registers with initial value = start offset - 1
+
+    // Address of register 0.
+    __ add(r1, frame_pointer(), Operand(kRegisterZero));
+    __ mov(r2, Operand(num_saved_registers_));
+    Label init_loop;
+    __ bind(&init_loop);
+    __ str(r0, MemOperand(r1, kPointerSize, NegPostIndex));
+    __ sub(r2, r2, Operand(1), SetCC);
+    __ b(ne, &init_loop);
+  }
+
+  // Initialize backtrack stack pointer.
+  __ ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd));
+  // Initialize code pointer register
+  __ mov(code_pointer(), Operand(masm_->CodeObject()));
+  // Load previous char as initial value of current character register.
+  Label at_start;
+  __ ldr(r0, MemOperand(frame_pointer(), kAtStart));
+  __ cmp(r0, Operand(0));
+  __ b(ne, &at_start);
+  LoadCurrentCharacterUnchecked(-1, 1);  // Load previous char.
+  __ jmp(&start_label_);
+  __ bind(&at_start);
+  __ mov(current_character(), Operand('\n'));
+  __ jmp(&start_label_);
+
+
+  // Exit code:
+  if (success_label_.is_linked()) {
+    // Save captures when successful.
+    __ bind(&success_label_);
+    if (num_saved_registers_ > 0) {
+      // copy captures to output
+      __ ldr(r1, MemOperand(frame_pointer(), kInputStart));
+      __ ldr(r0, MemOperand(frame_pointer(), kRegisterOutput));
+      __ sub(r1, end_of_input_address(), r1);
+      // r1 is length of input in bytes.
+      if (mode_ == UC16) {
+        __ mov(r1, Operand(r1, LSR, 1));
+      }
+      // r1 is length of input in characters.
+
+      ASSERT_EQ(0, num_saved_registers_ % 2);
+      // Always an even number of capture registers. This allows us to
+      // unroll the loop once to add an operation between a load of a register
+      // and the following use of that register.
+      for (int i = 0; i < num_saved_registers_; i += 2) {
+        __ ldr(r2, register_location(i));
+        __ ldr(r3, register_location(i + 1));
+        if (mode_ == UC16) {
+          __ add(r2, r1, Operand(r2, ASR, 1));
+          __ add(r3, r1, Operand(r3, ASR, 1));
+        } else {
+          __ add(r2, r1, Operand(r2));
+          __ add(r3, r1, Operand(r3));
+        }
+        __ str(r2, MemOperand(r0, kPointerSize, PostIndex));
+        __ str(r3, MemOperand(r0, kPointerSize, PostIndex));
+      }
+    }
+    __ mov(r0, Operand(SUCCESS));
+  }
+  // Exit and return r0
+  __ bind(&exit_label_);
+  // Skip sp past regexp registers and local variables..
+  __ mov(sp, frame_pointer());
+  // Restore registers r4..r11 and return (restoring lr to pc).
+  __ ldm(ia_w, sp, registers_to_retain | pc.bit());
+
+  // Backtrack code (branch target for conditional backtracks).
+  if (backtrack_label_.is_linked()) {
+    __ bind(&backtrack_label_);
+    Backtrack();
+  }
+
+  Label exit_with_exception;
+
+  // Preempt-code
+  if (check_preempt_label_.is_linked()) {
+    SafeCallTarget(&check_preempt_label_);
+
+    CallCheckStackGuardState(r0);
+    __ cmp(r0, Operand(0));
+    // If returning non-zero, we should end execution with the given
+    // result as return value.
+    __ b(ne, &exit_label_);
+
+    // String might have moved: Reload end of string from frame.
+    __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
+    SafeReturn();
+  }
+
+  // Backtrack stack overflow code.
+  if (stack_overflow_label_.is_linked()) {
+    SafeCallTarget(&stack_overflow_label_);
+    // Reached if the backtrack-stack limit has been hit.
+
+    Label grow_failed;
+
+    // Call GrowStack(backtrack_stackpointer())
+    int num_arguments = 2;
+    FrameAlign(num_arguments, r0);
+    __ mov(r0, backtrack_stackpointer());
+    __ add(r1, frame_pointer(), Operand(kStackHighEnd));
+    ExternalReference grow_stack =
+      ExternalReference::re_grow_stack();
+    CallCFunction(grow_stack, num_arguments);
+    // If return NULL, we have failed to grow the stack, and
+    // must exit with a stack-overflow exception.
+    __ cmp(r0, Operand(0));
+    __ b(eq, &exit_with_exception);
+    // Otherwise use return value as new stack pointer.
+    __ mov(backtrack_stackpointer(), r0);
+    // Restore saved registers and continue.
+    SafeReturn();
+  }
+
+  if (exit_with_exception.is_linked()) {
+    // If any of the code above needed to exit with an exception.
+    __ bind(&exit_with_exception);
+    // Exit with Result EXCEPTION(-1) to signal thrown exception.
+    __ mov(r0, Operand(EXCEPTION));
+    __ jmp(&exit_label_);
+  }
+
+  CodeDesc code_desc;
+  masm_->GetCode(&code_desc);
+  Handle<Code> code = Factory::NewCode(code_desc,
+                                       NULL,
+                                       Code::ComputeFlags(Code::REGEXP),
+                                       masm_->CodeObject());
+  LOG(RegExpCodeCreateEvent(*code, *source));
+  return Handle<Object>::cast(code);
+}
+
+
+void RegExpMacroAssemblerARM::GoTo(Label* to) {
+  BranchOrBacktrack(al, to);
+}
+
+
+void RegExpMacroAssemblerARM::IfRegisterGE(int reg,
+                                           int comparand,
+                                           Label* if_ge) {
+  __ ldr(r0, register_location(reg));
+  __ cmp(r0, Operand(comparand));
+  BranchOrBacktrack(ge, if_ge);
+}
+
+
+void RegExpMacroAssemblerARM::IfRegisterLT(int reg,
+                                           int comparand,
+                                           Label* if_lt) {
+  __ ldr(r0, register_location(reg));
+  __ cmp(r0, Operand(comparand));
+  BranchOrBacktrack(lt, if_lt);
+}
+
+
+void RegExpMacroAssemblerARM::IfRegisterEqPos(int reg,
+                                              Label* if_eq) {
+  __ ldr(r0, register_location(reg));
+  __ cmp(r0, Operand(current_input_offset()));
+  BranchOrBacktrack(eq, if_eq);
+}
+
+
+RegExpMacroAssembler::IrregexpImplementation
+    RegExpMacroAssemblerARM::Implementation() {
+  return kARMImplementation;
+}
+
+
+void RegExpMacroAssemblerARM::LoadCurrentCharacter(int cp_offset,
+                                                   Label* on_end_of_input,
+                                                   bool check_bounds,
+                                                   int characters) {
+  ASSERT(cp_offset >= -1);      // ^ and \b can look behind one character.
+  ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
+  if (check_bounds) {
+    CheckPosition(cp_offset + characters - 1, on_end_of_input);
+  }
+  LoadCurrentCharacterUnchecked(cp_offset, characters);
+}
+
+
+void RegExpMacroAssemblerARM::PopCurrentPosition() {
+  Pop(current_input_offset());
+}
+
+
+void RegExpMacroAssemblerARM::PopRegister(int register_index) {
+  Pop(r0);
+  __ str(r0, register_location(register_index));
+}
+
+
+static bool is_valid_memory_offset(int value) {
+  if (value < 0) value = -value;
+  return value < (1<<12);
+}
+
+
+void RegExpMacroAssemblerARM::PushBacktrack(Label* label) {
+  if (label->is_bound()) {
+    int target = label->pos();
+    __ mov(r0, Operand(target + Code::kHeaderSize - kHeapObjectTag));
+  } else {
+    int constant_offset = GetBacktrackConstantPoolEntry();
+    masm_->label_at_put(label, constant_offset);
+    // Reading pc-relative is based on the address 8 bytes ahead of
+    // the current opcode.
+    unsigned int offset_of_pc_register_read =
+      masm_->pc_offset() + Assembler::kPcLoadDelta;
+    int pc_offset_of_constant =
+      constant_offset - offset_of_pc_register_read;
+    ASSERT(pc_offset_of_constant < 0);
+    if (is_valid_memory_offset(pc_offset_of_constant)) {
+      masm_->BlockConstPoolBefore(masm_->pc_offset() + Assembler::kInstrSize);
+      __ ldr(r0, MemOperand(pc, pc_offset_of_constant));
+    } else {
+      // Not a 12-bit offset, so it needs to be loaded from the constant
+      // pool.
+      masm_->BlockConstPoolBefore(
+          masm_->pc_offset() + 2 * Assembler::kInstrSize);
+      __ mov(r0, Operand(pc_offset_of_constant + Assembler::kInstrSize));
+      __ ldr(r0, MemOperand(pc, r0));
+    }
+  }
+  Push(r0);
+  CheckStackLimit();
+}
+
+
+void RegExpMacroAssemblerARM::PushCurrentPosition() {
+  Push(current_input_offset());
+}
+
+
+void RegExpMacroAssemblerARM::PushRegister(int register_index,
+                                           StackCheckFlag check_stack_limit) {
+  __ ldr(r0, register_location(register_index));
+  Push(r0);
+  if (check_stack_limit) CheckStackLimit();
+}
+
+
+void RegExpMacroAssemblerARM::ReadCurrentPositionFromRegister(int reg) {
+  __ ldr(current_input_offset(), register_location(reg));
+}
+
+
+void RegExpMacroAssemblerARM::ReadStackPointerFromRegister(int reg) {
+  __ ldr(backtrack_stackpointer(), register_location(reg));
+  __ ldr(r0, MemOperand(frame_pointer(), kStackHighEnd));
+  __ add(backtrack_stackpointer(), backtrack_stackpointer(), Operand(r0));
+}
+
+
+void RegExpMacroAssemblerARM::SetRegister(int register_index, int to) {
+  ASSERT(register_index >= num_saved_registers_);  // Reserved for positions!
+  __ mov(r0, Operand(to));
+  __ str(r0, register_location(register_index));
+}
+
+
+void RegExpMacroAssemblerARM::Succeed() {
+  __ jmp(&success_label_);
+}
+
+
+void RegExpMacroAssemblerARM::WriteCurrentPositionToRegister(int reg,
+                                                             int cp_offset) {
+  if (cp_offset == 0) {
+    __ str(current_input_offset(), register_location(reg));
+  } else {
+    __ add(r0, current_input_offset(), Operand(cp_offset * char_size()));
+    __ str(r0, register_location(reg));
+  }
+}
+
+
+void RegExpMacroAssemblerARM::ClearRegisters(int reg_from, int reg_to) {
+  ASSERT(reg_from <= reg_to);
+  __ ldr(r0, MemOperand(frame_pointer(), kInputStartMinusOne));
+  for (int reg = reg_from; reg <= reg_to; reg++) {
+    __ str(r0, register_location(reg));
+  }
+}
+
+
+void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) {
+  __ ldr(r1, MemOperand(frame_pointer(), kStackHighEnd));
+  __ sub(r0, backtrack_stackpointer(), r1);
+  __ str(r0, register_location(reg));
+}
+
+
+// Private methods:
+
+void RegExpMacroAssemblerARM::CallCheckStackGuardState(Register scratch) {
+  int num_arguments = 3;
+  FrameAlign(num_arguments, scratch);
+  // RegExp code frame pointer.
+  __ mov(r2, frame_pointer());
+  // Code* of self.
+  __ mov(r1, Operand(masm_->CodeObject()));
+  // r0 becomes return address pointer.
+  ExternalReference stack_guard_check =
+      ExternalReference::re_check_stack_guard_state();
+  CallCFunctionUsingStub(stack_guard_check, num_arguments);
+}
+
+
+// Helper function for reading a value out of a stack frame.
+template <typename T>
+static T& frame_entry(Address re_frame, int frame_offset) {
+  return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
+}
+
+
+int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
+                                                  Code* re_code,
+                                                  Address re_frame) {
+  if (StackGuard::IsStackOverflow()) {
+    Top::StackOverflow();
+    return EXCEPTION;
+  }
+
+  // If not real stack overflow the stack guard was used to interrupt
+  // execution for another purpose.
+
+  // Prepare for possible GC.
+  HandleScope handles;
+  Handle<Code> code_handle(re_code);
+
+  Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
+  // Current string.
+  bool is_ascii = subject->IsAsciiRepresentation();
+
+  ASSERT(re_code->instruction_start() <= *return_address);
+  ASSERT(*return_address <=
+      re_code->instruction_start() + re_code->instruction_size());
+
+  Object* result = Execution::HandleStackGuardInterrupt();
+
+  if (*code_handle != re_code) {  // Return address no longer valid
+    int delta = *code_handle - re_code;
+    // Overwrite the return address on the stack.
+    *return_address += delta;
+  }
+
+  if (result->IsException()) {
+    return EXCEPTION;
+  }
+
+  // String might have changed.
+  if (subject->IsAsciiRepresentation() != is_ascii) {
+    // If we changed between an ASCII and an UC16 string, the specialized
+    // code cannot be used, and we need to restart regexp matching from
+    // scratch (including, potentially, compiling a new version of the code).
+    return RETRY;
+  }
+
+  // Otherwise, the content of the string might have moved. It must still
+  // be a sequential or external string with the same content.
+  // Update the start and end pointers in the stack frame to the current
+  // location (whether it has actually moved or not).
+  ASSERT(StringShape(*subject).IsSequential() ||
+      StringShape(*subject).IsExternal());
+
+  // The original start address of the characters to match.
+  const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
+
+  // Find the current start address of the same character at the current string
+  // position.
+  int start_index = frame_entry<int>(re_frame, kStartIndex);
+  const byte* new_address = StringCharacterPosition(*subject, start_index);
+
+  if (start_address != new_address) {
+    // If there is a difference, update the object pointer and start and end
+    // addresses in the RegExp stack frame to match the new value.
+    const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
+    int byte_length = end_address - start_address;
+    frame_entry<const String*>(re_frame, kInputString) = *subject;
+    frame_entry<const byte*>(re_frame, kInputStart) = new_address;
+    frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
+  }
+
+  return 0;
+}
+
+
+MemOperand RegExpMacroAssemblerARM::register_location(int register_index) {
+  ASSERT(register_index < (1<<30));
+  if (num_registers_ <= register_index) {
+    num_registers_ = register_index + 1;
+  }
+  return MemOperand(frame_pointer(),
+                    kRegisterZero - register_index * kPointerSize);
+}
+
+
+void RegExpMacroAssemblerARM::CheckPosition(int cp_offset,
+                                            Label* on_outside_input) {
+  __ cmp(current_input_offset(), Operand(-cp_offset * char_size()));
+  BranchOrBacktrack(ge, on_outside_input);
+}
+
+
+void RegExpMacroAssemblerARM::BranchOrBacktrack(Condition condition,
+                                                Label* to) {
+  if (condition == al) {  // Unconditional.
+    if (to == NULL) {
+      Backtrack();
+      return;
+    }
+    __ jmp(to);
+    return;
+  }
+  if (to == NULL) {
+    __ b(condition, &backtrack_label_);
+    return;
+  }
+  __ b(condition, to);
+}
+
+
+void RegExpMacroAssemblerARM::SafeCall(Label* to, Condition cond) {
+  __ bl(to, cond);
+}
+
+
+void RegExpMacroAssemblerARM::SafeReturn() {
+  __ pop(lr);
+  __ add(pc, lr, Operand(masm_->CodeObject()));
+}
+
+
+void RegExpMacroAssemblerARM::SafeCallTarget(Label* name) {
+  __ bind(name);
+  __ sub(lr, lr, Operand(masm_->CodeObject()));
+  __ push(lr);
+}
+
+
+void RegExpMacroAssemblerARM::Push(Register source) {
+  ASSERT(!source.is(backtrack_stackpointer()));
+  __ str(source,
+         MemOperand(backtrack_stackpointer(), kPointerSize, NegPreIndex));
+}
+
+
+void RegExpMacroAssemblerARM::Pop(Register target) {
+  ASSERT(!target.is(backtrack_stackpointer()));
+  __ ldr(target,
+         MemOperand(backtrack_stackpointer(), kPointerSize, PostIndex));
+}
+
+
+void RegExpMacroAssemblerARM::CheckPreemption() {
+  // Check for preemption.
+  ExternalReference stack_guard_limit =
+      ExternalReference::address_of_stack_guard_limit();
+  __ mov(r0, Operand(stack_guard_limit));
+  __ ldr(r0, MemOperand(r0));
+  __ cmp(sp, r0);
+  SafeCall(&check_preempt_label_, ls);
+}
+
+
+void RegExpMacroAssemblerARM::CheckStackLimit() {
+  if (FLAG_check_stack) {
+    ExternalReference stack_limit =
+        ExternalReference::address_of_regexp_stack_limit();
+    __ mov(r0, Operand(stack_limit));
+    __ ldr(r0, MemOperand(r0));
+    __ cmp(backtrack_stackpointer(), Operand(r0));
+    SafeCall(&stack_overflow_label_, ls);
+  }
+}
+
+
+void RegExpMacroAssemblerARM::EmitBacktrackConstantPool() {
+  __ CheckConstPool(false, false);
+  __ BlockConstPoolBefore(
+      masm_->pc_offset() + kBacktrackConstantPoolSize * Assembler::kInstrSize);
+  backtrack_constant_pool_offset_ = masm_->pc_offset();
+  for (int i = 0; i < kBacktrackConstantPoolSize; i++) {
+    __ emit(0);
+  }
+
+  backtrack_constant_pool_capacity_ = kBacktrackConstantPoolSize;
+}
+
+
+int RegExpMacroAssemblerARM::GetBacktrackConstantPoolEntry() {
+  while (backtrack_constant_pool_capacity_ > 0) {
+    int offset = backtrack_constant_pool_offset_;
+    backtrack_constant_pool_offset_ += kPointerSize;
+    backtrack_constant_pool_capacity_--;
+    if (masm_->pc_offset() - offset < 2 * KB) {
+      return offset;
+    }
+  }
+  Label new_pool_skip;
+  __ jmp(&new_pool_skip);
+  EmitBacktrackConstantPool();
+  __ bind(&new_pool_skip);
+  int offset = backtrack_constant_pool_offset_;
+  backtrack_constant_pool_offset_ += kPointerSize;
+  backtrack_constant_pool_capacity_--;
+  return offset;
+}
+
+
+void RegExpMacroAssemblerARM::FrameAlign(int num_arguments, Register scratch) {
+  int frameAlignment = OS::ActivationFrameAlignment();
+  // Up to four simple arguments are passed in registers r0..r3.
+  int stack_passed_arguments = (num_arguments <= 4) ? 0 : num_arguments - 4;
+  if (frameAlignment != 0) {
+    // Make stack end at alignment and make room for num_arguments - 4 words
+    // and the original value of sp.
+    __ mov(scratch, sp);
+    __ sub(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize));
+    ASSERT(IsPowerOf2(frameAlignment));
+    __ and_(sp, sp, Operand(-frameAlignment));
+    __ str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
+  } else {
+    __ sub(sp, sp, Operand(stack_passed_arguments * kPointerSize));
+  }
+}
+
+
+void RegExpMacroAssemblerARM::CallCFunction(ExternalReference function,
+                                            int num_arguments) {
+  __ mov(r5, Operand(function));
+  // Just call directly. The function called cannot cause a GC, or
+  // allow preemption, so the return address in the link register
+  // stays correct.
+  __ Call(r5);
+  int stack_passed_arguments = (num_arguments <= 4) ? 0 : num_arguments - 4;
+  if (OS::ActivationFrameAlignment() > kIntSize) {
+    __ ldr(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
+  } else {
+    __ add(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize)));
+  }
+  __ mov(code_pointer(), Operand(masm_->CodeObject()));
+}
+
+
+void RegExpMacroAssemblerARM::CallCFunctionUsingStub(
+    ExternalReference function,
+    int num_arguments) {
+  // Must pass all arguments in registers. The stub pushes on the stack.
+  ASSERT(num_arguments <= 4);
+  __ mov(r5, Operand(function));
+  RegExpCEntryStub stub;
+  __ CallStub(&stub);
+  if (OS::ActivationFrameAlignment() != 0) {
+    __ ldr(sp, MemOperand(sp, 0));
+  }
+  __ mov(code_pointer(), Operand(masm_->CodeObject()));
+}
+
+
+void RegExpMacroAssemblerARM::LoadCurrentCharacterUnchecked(int cp_offset,
+                                                            int characters) {
+  Register offset = current_input_offset();
+  if (cp_offset != 0) {
+    __ add(r0, current_input_offset(), Operand(cp_offset * char_size()));
+    offset = r0;
+  }
+  // We assume that we cannot do unaligned loads on ARM, so this function
+  // must only be used to load a single character at a time.
+  ASSERT(characters == 1);
+  if (mode_ == ASCII) {
+    __ ldrb(current_character(), MemOperand(end_of_input_address(), offset));
+  } else {
+    ASSERT(mode_ == UC16);
+    __ ldrh(current_character(), MemOperand(end_of_input_address(), offset));
+  }
+}
+
+
+void RegExpCEntryStub::Generate(MacroAssembler* masm_) {
+  int stack_alignment = OS::ActivationFrameAlignment();
+  if (stack_alignment < kPointerSize) stack_alignment = kPointerSize;
+  // Stack is already aligned for call, so decrement by alignment
+  // to make room for storing the link register.
+  __ str(lr, MemOperand(sp, stack_alignment, NegPreIndex));
+  __ mov(r0, sp);
+  __ Call(r5);
+  __ ldr(pc, MemOperand(sp, stack_alignment, PostIndex));
+}
+
+#undef __
+
+#endif  // V8_NATIVE_REGEXP
+
+}}  // namespace v8::internal
index de5518379cad2ac3a7df08c7dd43b60c8584dded..2d0bd442b9977e945ebbdd3a8698c0bfbf4ad64e 100644 (file)
 namespace v8 {
 namespace internal {
 
+
+#ifndef V8_NATIVE_REGEXP
 class RegExpMacroAssemblerARM: public RegExpMacroAssembler {
  public:
   RegExpMacroAssemblerARM();
   virtual ~RegExpMacroAssemblerARM();
 };
 
+#else
+class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler {
+ public:
+  RegExpMacroAssemblerARM(Mode mode, int registers_to_save);
+  virtual ~RegExpMacroAssemblerARM();
+  virtual int stack_limit_slack();
+  virtual bool CanReadUnaligned();
+  virtual void AdvanceCurrentPosition(int by);
+  virtual void AdvanceRegister(int reg, int by);
+  virtual void Backtrack();
+  virtual void Bind(Label* label);
+  virtual void CheckAtStart(Label* on_at_start);
+  virtual void CheckCharacter(uint32_t c, Label* on_equal);
+  virtual void CheckCharacterAfterAnd(uint32_t c,
+                                      uint32_t mask,
+                                      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,
+                               bool check_end_of_string);
+  // A "greedy loop" is a loop that is both greedy and with a simple
+  // body. It has a particularly simple implementation.
+  virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
+  virtual void CheckNotAtStart(Label* on_not_at_start);
+  virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
+  virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
+                                               Label* on_no_match);
+  virtual void CheckNotRegistersEqual(int reg1, int reg2, Label* on_not_equal);
+  virtual void CheckNotCharacter(uint32_t c, Label* on_not_equal);
+  virtual void CheckNotCharacterAfterAnd(uint32_t c,
+                                         uint32_t mask,
+                                         Label* on_not_equal);
+  virtual void CheckNotCharacterAfterMinusAnd(uc16 c,
+                                              uc16 minus,
+                                              uc16 mask,
+                                              Label* on_not_equal);
+  // Checks whether the given offset from the current position is before
+  // the end of the string.
+  virtual void CheckPosition(int cp_offset, Label* on_outside_input);
+  virtual bool CheckSpecialCharacterClass(uc16 type,
+                                          int cp_offset,
+                                          bool check_offset,
+                                          Label* on_no_match);
+  virtual void Fail();
+  virtual Handle<Object> GetCode(Handle<String> source);
+  virtual void GoTo(Label* label);
+  virtual void IfRegisterGE(int reg, int comparand, Label* if_ge);
+  virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
+  virtual void IfRegisterEqPos(int reg, Label* if_eq);
+  virtual IrregexpImplementation Implementation();
+  virtual void LoadCurrentCharacter(int cp_offset,
+                                    Label* on_end_of_input,
+                                    bool check_bounds = true,
+                                    int characters = 1);
+  virtual void PopCurrentPosition();
+  virtual void PopRegister(int register_index);
+  virtual void PushBacktrack(Label* label);
+  virtual void PushCurrentPosition();
+  virtual void PushRegister(int register_index,
+                            StackCheckFlag check_stack_limit);
+  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, int cp_offset);
+  virtual void ClearRegisters(int reg_from, int reg_to);
+  virtual void WriteStackPointerToRegister(int reg);
+
+  // Called from RegExp if the stack-guard is triggered.
+  // If the code object is relocated, the return address is fixed before
+  // returning.
+  static int CheckStackGuardState(Address* return_address,
+                                  Code* re_code,
+                                  Address re_frame);
+ private:
+  // Offsets from frame_pointer() of function parameters and stored registers.
+  static const int kFramePointer = 0;
+
+  // Above the frame pointer - Stored registers and stack passed parameters.
+  // Register 4..11.
+  static const int kStoredRegisters = kFramePointer;
+  // Return address (stored from link register, read into pc on return).
+  static const int kReturnAddress = kStoredRegisters + 8 * kPointerSize;
+  // Stack parameters placed by caller.
+  static const int kRegisterOutput = kReturnAddress + kPointerSize;
+  static const int kAtStart = kRegisterOutput + kPointerSize;
+  static const int kStackHighEnd = kAtStart + kPointerSize;
+
+  // Below the frame pointer.
+  // Register parameters stored by setup code.
+  static const int kInputEnd = kFramePointer - kPointerSize;
+  static const int kInputStart = kInputEnd - kPointerSize;
+  static const int kStartIndex = kInputStart - kPointerSize;
+  static const int kInputString = kStartIndex - kPointerSize;
+  // When adding local variables remember to push space for them in
+  // the frame in GetCode.
+  static const int kInputStartMinusOne = kInputString - kPointerSize;
+  // First register address. Following registers are below it on the stack.
+  static const int kRegisterZero = kInputStartMinusOne - kPointerSize;
+
+  // Initial size of code buffer.
+  static const size_t kRegExpCodeSize = 1024;
+
+  static const int kBacktrackConstantPoolSize = 4;
+
+  // Load a number of characters at the given offset from the
+  // current position, into the current-character register.
+  void LoadCurrentCharacterUnchecked(int cp_offset, int character_count);
+
+  // Check whether preemption has been requested.
+  void CheckPreemption();
+
+  // Check whether we are exceeding the stack limit on the backtrack stack.
+  void CheckStackLimit();
+
+  void EmitBacktrackConstantPool();
+  int GetBacktrackConstantPoolEntry();
+
+
+  // Generate a call to CheckStackGuardState.
+  void CallCheckStackGuardState(Register scratch);
+
+  // The ebp-relative location of a regexp register.
+  MemOperand register_location(int register_index);
+
+  // Register holding the current input position as negative offset from
+  // the end of the string.
+  inline Register current_input_offset() { return r6; }
+
+  // The register containing the current character after LoadCurrentCharacter.
+  inline Register current_character() { return r7; }
+
+  // Register holding address of the end of the input string.
+  inline Register end_of_input_address() { return r10; }
+
+  // Register holding the frame address. Local variables, parameters and
+  // regexp registers are addressed relative to this.
+  inline Register frame_pointer() { return fp; }
+
+  // The register containing the backtrack stack top. Provides a meaningful
+  // name to the register.
+  inline Register backtrack_stackpointer() { return r8; }
+
+  // Register holding pointer to the current code object.
+  inline Register code_pointer() { return r5; }
+
+  // Byte size of chars in the string to match (decided by the Mode argument)
+  inline int char_size() { return static_cast<int>(mode_); }
+
+  // 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);
+
+  // Call and return internally in the generated code in a way that
+  // is GC-safe (i.e., doesn't leave absolute code addresses on the stack)
+  inline void SafeCall(Label* to, Condition cond = al);
+  inline void SafeReturn();
+  inline void SafeCallTarget(Label* name);
+
+  // Pushes the value of a register on the backtrack stack. Decrements the
+  // stack pointer by a word size and stores the register's value there.
+  inline void Push(Register source);
+
+  // Pops a value from the backtrack stack. Reads the word at the stack pointer
+  // and increments it by a word size.
+  inline void Pop(Register target);
+
+  // Before calling a C-function from generated code, align arguments on stack.
+  // After aligning the frame, non-register arguments must be stored in
+  // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments
+  // are word sized.
+  // Some compilers/platforms require the stack to be aligned when calling
+  // C++ code.
+  // Needs a scratch register to do some arithmetic. This register will be
+  // trashed.
+  inline void FrameAlign(int num_arguments, Register scratch);
+
+  // Calls a C function and cleans up the space for arguments allocated
+  // by FrameAlign. The called function is not allowed to trigger a garbage
+  // collection.
+  inline void CallCFunction(ExternalReference function,
+                            int num_arguments);
+
+  // Calls a C function and cleans up the frame alignment done by
+  // by FrameAlign. The called function *is* allowed to trigger a garbage
+  // collection, but may not take more than four arguments (no arguments
+  // passed on the stack), and the first argument will be a pointer to the
+  // return address.
+  inline void CallCFunctionUsingStub(ExternalReference function,
+                                     int num_arguments);
+
+
+  MacroAssembler* masm_;
+
+  // Which mode to generate code for (ASCII or UC16).
+  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_;
+
+  // Manage a small pre-allocated pool for writing label targets
+  // to for pushing backtrack addresses.
+  int backtrack_constant_pool_offset_;
+  int backtrack_constant_pool_capacity_;
+
+  // Labels used internally.
+  Label entry_label_;
+  Label start_label_;
+  Label success_label_;
+  Label backtrack_label_;
+  Label exit_label_;
+  Label check_preempt_label_;
+  Label stack_overflow_label_;
+};
+
+
+#endif  // V8_NATIVE_REGEXP
+
+
 }}  // namespace v8::internal
 
 #endif  // V8_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_
index d12ddbfaa71f04c02d2c243a8dc90e71283a0987..e258e5a686a0e9b446c4b919628b0d14cbc5057e 100644 (file)
@@ -26,7 +26,7 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <stdlib.h>
-
+#include <cstdarg>
 #include "v8.h"
 
 #include "disasm.h"
@@ -598,7 +598,7 @@ uint16_t Simulator::ReadHU(int32_t addr, Instr* instr) {
     uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
     return *ptr;
   }
-  PrintF("Unaligned read at %x, pc=%p\n", addr, instr);
+  PrintF("Unaligned unsigned halfword read at %x, pc=%p\n", addr, instr);
   UNIMPLEMENTED();
   return 0;
 }
@@ -609,7 +609,7 @@ int16_t Simulator::ReadH(int32_t addr, Instr* instr) {
     int16_t* ptr = reinterpret_cast<int16_t*>(addr);
     return *ptr;
   }
-  PrintF("Unaligned read at %x\n", addr);
+  PrintF("Unaligned signed halfword read at %x\n", addr);
   UNIMPLEMENTED();
   return 0;
 }
@@ -621,7 +621,7 @@ void Simulator::WriteH(int32_t addr, uint16_t value, Instr* instr) {
     *ptr = value;
     return;
   }
-  PrintF("Unaligned write at %x, pc=%p\n", addr, instr);
+  PrintF("Unaligned unsigned halfword write at %x, pc=%p\n", addr, instr);
   UNIMPLEMENTED();
 }
 
@@ -632,7 +632,7 @@ void Simulator::WriteH(int32_t addr, int16_t value, Instr* instr) {
     *ptr = value;
     return;
   }
-  PrintF("Unaligned write at %x, pc=%p\n", addr, instr);
+  PrintF("Unaligned halfword write at %x, pc=%p\n", addr, instr);
   UNIMPLEMENTED();
 }
 
@@ -1416,8 +1416,12 @@ void Simulator::DecodeType01(Instr* instr) {
 
       case CMN: {
         if (instr->HasS()) {
-          Format(instr, "cmn'cond 'rn, 'shift_rm");
-          Format(instr, "cmn'cond 'rn, 'imm");
+          // Format(instr, "cmn'cond 'rn, 'shift_rm");
+          // Format(instr, "cmn'cond 'rn, 'imm");
+          alu_out = rn_val + shifter_operand;
+          SetNZFlags(alu_out);
+          SetCFlag(!CarryFrom(rn_val, shifter_operand));
+          SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
         } else {
           ASSERT(type == 0);
           int rm = instr->RmField();
@@ -1566,6 +1570,7 @@ void Simulator::DecodeType2(Instr* instr) {
 
 
 void Simulator::DecodeType3(Instr* instr) {
+  ASSERT(instr->Bit(4) == 0);
   int rd = instr->RdField();
   int rn = instr->RnField();
   int32_t rn_val = get_register(rn);
@@ -1605,7 +1610,12 @@ void Simulator::DecodeType3(Instr* instr) {
     }
   }
   if (instr->HasB()) {
-    UNIMPLEMENTED();
+    if (instr->HasL()) {
+      uint8_t byte = ReadB(addr);
+      set_register(rd, byte);
+    } else {
+      UNIMPLEMENTED();
+    }
   } else {
     if (instr->HasL()) {
       set_register(rd, ReadW(addr, instr));
@@ -1630,12 +1640,13 @@ void Simulator::DecodeType4(Instr* instr) {
 
 void Simulator::DecodeType5(Instr* instr) {
   // Format(instr, "b'l'cond 'target");
-  int off = (instr->SImmed24Field() << 2) + 8;
-  intptr_t pc = get_pc();
+  int off = (instr->SImmed24Field() << 2);
+  intptr_t pc_address = get_pc();
   if (instr->HasLink()) {
-    set_register(lr, pc + Instr::kInstrSize);
+    set_register(lr, pc_address + Instr::kInstrSize);
   }
-  set_pc(pc+off);
+  int pc_reg = get_register(pc);
+  set_pc(pc_reg + off);
 }
 
 
@@ -1654,14 +1665,75 @@ void Simulator::DecodeType7(Instr* instr) {
 }
 
 
+void Simulator::DecodeUnconditional(Instr* instr) {
+  if (instr->Bits(7, 4) == 0x0B && instr->Bits(27, 25) == 0 && instr->HasL()) {
+    // Load halfword instruction, either register or immediate offset.
+    int rd = instr->RdField();
+    int rn = instr->RnField();
+    int32_t rn_val = get_register(rn);
+    int32_t addr = 0;
+    int32_t offset;
+    if (instr->Bit(22) == 0) {
+      // Register offset.
+      int rm = instr->RmField();
+      offset = get_register(rm);
+    } else {
+      // Immediate offset
+      offset = instr->Bits(3, 0) + (instr->Bits(11, 8) << 4);
+    }
+    switch (instr->PUField()) {
+      case 0: {
+        // Post index, negative.
+        ASSERT(!instr->HasW());
+        addr = rn_val;
+        rn_val -= offset;
+        set_register(rn, rn_val);
+        break;
+      }
+      case 1: {
+        // Post index, positive.
+        ASSERT(!instr->HasW());
+        addr = rn_val;
+        rn_val += offset;
+        set_register(rn, rn_val);
+        break;
+      }
+      case 2: {
+        // Pre index or offset, negative.
+        rn_val -= offset;
+        addr = rn_val;
+        if (instr->HasW()) {
+          set_register(rn, rn_val);
+        }
+        break;
+      }
+      case 3: {
+        // Pre index or offset, positive.
+        rn_val += offset;
+        addr = rn_val;
+        if (instr->HasW()) {
+          set_register(rn, rn_val);
+        }
+        break;
+      }
+      default: {
+        // The PU field is a 2-bit field.
+        UNREACHABLE();
+        break;
+      }
+    }
+    // Not sign extending, so load as unsigned.
+    uint16_t halfword = ReadH(addr, instr);
+    set_register(rd, halfword);
+  } else {
+    UNIMPLEMENTED();
+  }
+}
+
+
 // Executes the current instruction.
 void Simulator::InstructionDecode(Instr* instr) {
   pc_modified_ = false;
-  if (instr->ConditionField() == special_condition) {
-    Debugger dbg(this);
-    dbg.Stop(instr);
-    return;
-  }
   if (::v8::internal::FLAG_trace_sim) {
     disasm::NameConverter converter;
     disasm::Disassembler dasm(converter);
@@ -1671,7 +1743,9 @@ void Simulator::InstructionDecode(Instr* instr) {
                            reinterpret_cast<byte*>(instr));
     PrintF("  0x%x  %s\n", instr, buffer.start());
   }
-  if (ConditionallyExecute(instr)) {
+  if (instr->ConditionField() == special_condition) {
+    DecodeUnconditional(instr);
+  } else if (ConditionallyExecute(instr)) {
     switch (instr->TypeField()) {
       case 0:
       case 1: {
@@ -1747,19 +1821,35 @@ void Simulator::Execute() {
 }
 
 
-Object* Simulator::Call(int32_t entry, int32_t p0, int32_t p1, int32_t p2,
-                        int32_t p3, int32_t p4) {
-  // Setup parameters
-  set_register(r0, p0);
-  set_register(r1, p1);
-  set_register(r2, p2);
-  set_register(r3, p3);
-  intptr_t* stack_pointer = reinterpret_cast<intptr_t*>(get_register(sp));
-  *(--stack_pointer) = p4;
-  set_register(sp, reinterpret_cast<int32_t>(stack_pointer));
+int32_t Simulator::Call(byte* entry, int argument_count, ...) {
+  va_list parameters;
+  va_start(parameters, argument_count);
+  // Setup arguments
+
+  // First four arguments passed in registers.
+  ASSERT(argument_count >= 4);
+  set_register(r0, va_arg(parameters, int32_t));
+  set_register(r1, va_arg(parameters, int32_t));
+  set_register(r2, va_arg(parameters, int32_t));
+  set_register(r3, va_arg(parameters, int32_t));
+
+  // Remaining arguments passed on stack.
+  int original_stack = get_register(sp);
+  // Compute position of stack on entry to generated code.
+  int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t));
+  if (OS::ActivationFrameAlignment() != 0) {
+    entry_stack &= -OS::ActivationFrameAlignment();
+  }
+  // Store remaining arguments on stack, from low to high memory.
+  intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
+  for (int i = 4; i < argument_count; i++) {
+    stack_argument[i - 4] = va_arg(parameters, int32_t);
+  }
+  va_end(parameters);
+  set_register(sp, entry_stack);
 
   // Prepare to execute the code at entry
-  set_register(pc, entry);
+  set_register(pc, reinterpret_cast<int32_t>(entry));
   // Put down marker for end of simulation. The simulator will stop simulation
   // when the PC reaches this value. By saving the "end simulation" value into
   // the LR the simulation stops when returning to this call point.
@@ -1793,14 +1883,14 @@ Object* Simulator::Call(int32_t entry, int32_t p0, int32_t p1, int32_t p2,
   Execute();
 
   // Check that the callee-saved registers have been preserved.
-  CHECK_EQ(get_register(r4), callee_saved_value);
-  CHECK_EQ(get_register(r5), callee_saved_value);
-  CHECK_EQ(get_register(r6), callee_saved_value);
-  CHECK_EQ(get_register(r7), callee_saved_value);
-  CHECK_EQ(get_register(r8), callee_saved_value);
-  CHECK_EQ(get_register(r9), callee_saved_value);
-  CHECK_EQ(get_register(r10), callee_saved_value);
-  CHECK_EQ(get_register(r11), callee_saved_value);
+  CHECK_EQ(callee_saved_value, get_register(r4));
+  CHECK_EQ(callee_saved_value, get_register(r5));
+  CHECK_EQ(callee_saved_value, get_register(r6));
+  CHECK_EQ(callee_saved_value, get_register(r7));
+  CHECK_EQ(callee_saved_value, get_register(r8));
+  CHECK_EQ(callee_saved_value, get_register(r9));
+  CHECK_EQ(callee_saved_value, get_register(r10));
+  CHECK_EQ(callee_saved_value, get_register(r11));
 
   // Restore callee-saved registers with the original value.
   set_register(r4, r4_val);
@@ -1812,8 +1902,12 @@ Object* Simulator::Call(int32_t entry, int32_t p0, int32_t p1, int32_t p2,
   set_register(r10, r10_val);
   set_register(r11, r11_val);
 
-  int result = get_register(r0);
-  return reinterpret_cast<Object*>(result);
+  // Pop stack passed arguments.
+  CHECK_EQ(entry_stack, get_register(sp));
+  set_register(sp, original_stack);
+
+  int32_t result = get_register(r0);
+  return result;
 }
 
 } }  // namespace assembler::arm
index 15b92a5f82ca54219b58b70e954aaf00cd55842c..3917d6a5af1bc4c82b68be3e2b07c56cc60741b1 100644 (file)
@@ -40,7 +40,7 @@
 
 // When running without a simulator we call the entry directly.
 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
-  reinterpret_cast<Object*>(entry(p0, p1, p2, p3, p4))
+  (entry(p0, p1, p2, p3, p4))
 
 // Calculated the stack limit beyond which we will throw stack overflow errors.
 // This macro must be called from a C++ method. It relies on being able to take
 #define GENERATED_CODE_STACK_LIMIT(limit) \
   (reinterpret_cast<uintptr_t>(this) - limit)
 
+
+// Call the generated regexp code directly. The entry function pointer should
+// expect seven int/pointer sized arguments and return an int.
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
+  entry(p0, p1, p2, p3, p4, p5, p6)
+
 #else  // defined(__arm__)
 
 // When running with the simulator transition into simulated execution at this
 // point.
 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
-  assembler::arm::Simulator::current()->Call((int32_t)entry, (int32_t)p0, \
-    (int32_t)p1, (int32_t)p2, (int32_t)p3, (int32_t)p4)
+  reinterpret_cast<Object*>( \
+      assembler::arm::Simulator::current()->Call(FUNCTION_ADDR(entry), 5, \
+                                                 p0, p1, p2, p3, p4))
 
 // The simulator has its own stack. Thus it has a different stack limit from
 // the C-based native code.
   (assembler::arm::Simulator::current()->StackLimit())
 
 
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
+  assembler::arm::Simulator::current()->Call( \
+    FUNCTION_ADDR(entry), 7, p0, p1, p2, p3, p4, p5, p6)
+
 #include "constants-arm.h"
 
 
@@ -109,11 +120,10 @@ class Simulator {
   // Call on program start.
   static void Initialize();
 
-  // V8 generally calls into generated code with 5 parameters. This is a
-  // convenience function, which sets up the simulator state and grabs the
-  // result on return.
-  v8::internal::Object* Call(int32_t entry, int32_t p0, int32_t p1,
-                             int32_t p2, int32_t p3, int32_t p4);
+  // V8 generally calls into generated JS code with 5 parameters and into
+  // generated RegExp code with 7 parameters. This is a convenience function,
+  // which sets up the simulator state and grabs the result on return.
+  int32_t Call(byte* entry, int argument_count, ...);
 
  private:
   enum special_values {
@@ -174,6 +184,7 @@ class Simulator {
   void DecodeType5(Instr* instr);
   void DecodeType6(Instr* instr);
   void DecodeType7(Instr* instr);
+  void DecodeUnconditional(Instr* instr);
 
   // Executes one instruction.
   void InstructionDecode(Instr* instr);
index 546490ee38bde2d524b06802fb6752b8f2941e02..3563ebd2e2e3989c9f379e70d01edae119c7e572 100644 (file)
 #include "serialize.h"
 #include "stub-cache.h"
 #include "regexp-stack.h"
+#include "ast.h"
+#include "regexp-macro-assembler.h"
+// Include native regexp-macro-assembler.
+#ifdef V8_NATIVE_REGEXP
+#if V8_TARGET_ARCH_IA32
+#include "ia32/regexp-macro-assembler-ia32.h"
+#elif V8_TARGET_ARCH_X64
+#include "x64/regexp-macro-assembler-x64.h"
+#elif V8_TARGET_ARCH_ARM
+#include "arm/regexp-macro-assembler-arm.h"
+#else  // Unknown architecture.
+#error "Unknown architecture."
+#endif  // Target architecture.
+#endif  // V8_NATIVE_REGEXP
 
 namespace v8 {
 namespace internal {
@@ -597,6 +611,34 @@ ExternalReference ExternalReference::new_space_allocation_limit_address() {
   return ExternalReference(Heap::NewSpaceAllocationLimitAddress());
 }
 
+#ifdef V8_NATIVE_REGEXP
+
+ExternalReference ExternalReference::re_check_stack_guard_state() {
+  Address function;
+#ifdef V8_TARGET_ARCH_X64
+  function = FUNCTION_ADDR(RegExpMacroAssemblerX64::CheckStackGuardState);
+#elif V8_TARGET_ARCH_IA32
+  function = FUNCTION_ADDR(RegExpMacroAssemblerIA32::CheckStackGuardState);
+#elif V8_TARGET_ARCH_ARM
+  function = FUNCTION_ADDR(RegExpMacroAssemblerARM::CheckStackGuardState);
+#else
+  UNREACHABLE("Unexpected architecture");
+#endif
+  return ExternalReference(Redirect(function));
+}
+
+ExternalReference ExternalReference::re_grow_stack() {
+  return ExternalReference(
+      Redirect(FUNCTION_ADDR(NativeRegExpMacroAssembler::GrowStack)));
+}
+
+ExternalReference ExternalReference::re_case_insensitive_compare_uc16() {
+  return ExternalReference(Redirect(
+      FUNCTION_ADDR(NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16)));
+}
+
+#endif
+
 
 static double add_two_doubles(double x, double y) {
   return x + y;
index e217918ceea51ca90d6808448b643b6b21cef559..827389a1b6f3855235c7ac64903a5b3fa4743658 100644 (file)
@@ -431,6 +431,19 @@ class ExternalReference BASE_EMBEDDED {
   static ExternalReference debug_step_in_fp_address();
 #endif
 
+#ifdef V8_NATIVE_REGEXP
+  // C functions called from RegExp generated code.
+
+  // Function NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16()
+  static ExternalReference re_case_insensitive_compare_uc16();
+
+  // Function RegExpMacroAssembler*::CheckStackGuardState()
+  static ExternalReference re_check_stack_guard_state();
+
+  // Function NativeRegExpMacroAssembler::GrowStack()
+  static ExternalReference re_grow_stack();
+#endif
+
   // This lets you register a function that rewrites all external references.
   // Used by the ARM simulator to catch calls to external references.
   static void set_redirector(ExternalReferenceRedirector* redirector) {
index 76ec7870f32b15b5b7aec14a158bf7d39e72e075..ae86c20ef6c637e21aac32162b48311eae80e92c 100644 (file)
@@ -57,6 +57,7 @@ class CodeStub BASE_EMBEDDED {
     SetProperty,   // ARM only
     InvokeBuiltin,  // ARM only
     JSExit,        // ARM only
+    RegExpCEntry,  // ARM only
     NUMBER_OF_IDS
   };
 
index 3b8ee92ff8c4aa683cd580686260f602aa42d60f..efe0127e0a6e8520f9cd3e4cdb024242a9286dae 100644 (file)
@@ -47,7 +47,14 @@ namespace internal {
 #define V8_HOST_ARCH_ARM 1
 #define V8_HOST_ARCH_32_BIT 1
 #else
-#error Your architecture was not detected as supported by v8
+#error Your host architecture was not detected as supported by v8
+#endif
+
+#if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_IA32)
+#define V8_TARGET_CAN_READ_UNALIGNED 1
+#elif V8_TARGET_ARCH_ARM
+#else
+#error Your target architecture is not supported by v8
 #endif
 
 // Support for alternative bool type. This is only enabled if the code is
index 19eb42eedfcda7651b3e5c8fc02651ac67d18ab4..c9128ae0baff8cc5f42fd8c5c2ad312dae7d94d0 100644 (file)
@@ -39,6 +39,9 @@
 #include "scanner.h"
 #include "scopeinfo.h"
 #include "v8threads.h"
+#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
+#include "regexp-macro-assembler.h"
+#endif
 
 namespace v8 {
 namespace internal {
@@ -1320,6 +1323,14 @@ void Heap::CreateCEntryStub() {
 }
 
 
+#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
+void Heap::CreateRegExpCEntryStub() {
+  RegExpCEntryStub stub;
+  set_re_c_entry_code(*stub.GetCode());
+}
+#endif
+
+
 void Heap::CreateCEntryDebugBreakStub() {
   CEntryDebugBreakStub stub;
   set_c_entry_debug_break_code(*stub.GetCode());
@@ -1356,6 +1367,9 @@ void Heap::CreateFixedStubs() {
   Heap::CreateCEntryDebugBreakStub();
   Heap::CreateJSEntryStub();
   Heap::CreateJSConstructEntryStub();
+#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
+  Heap::CreateRegExpCEntryStub();
+#endif
 }
 
 
index 8b0919e9336adf6c0793df0f747d44a411328c5d..fa4830672b772cb1577e35ee0c2221804977d882 100644 (file)
@@ -34,7 +34,7 @@ namespace v8 {
 namespace internal {
 
 // Defines all the roots in Heap.
-#define STRONG_ROOT_LIST(V)                                                    \
+#define UNCONDITIONAL_STRONG_ROOT_LIST(V)                                      \
   /* Cluster the most popular ones in a few cache lines here at the top. */    \
   V(Smi, stack_limit, StackLimit)                                              \
   V(Object, undefined_value, UndefinedValue)                                   \
@@ -136,6 +136,13 @@ namespace internal {
   V(FixedArray, natives_source_cache, NativesSourceCache)                      \
   V(Object, last_script_id, LastScriptId)                                      \
 
+#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
+#define STRONG_ROOT_LIST(V)                                                    \
+  UNCONDITIONAL_STRONG_ROOT_LIST(V)                                            \
+  V(Code, re_c_entry_code, RegExpCEntryCode)
+#else
+#define STRONG_ROOT_LIST(V) UNCONDITIONAL_STRONG_ROOT_LIST(V)
+#endif
 
 #define ROOT_LIST(V)                                  \
   STRONG_ROOT_LIST(V)                                 \
@@ -1025,6 +1032,8 @@ class Heap : public AllStatic {
   static void CreateCEntryDebugBreakStub();
   static void CreateJSEntryStub();
   static void CreateJSConstructEntryStub();
+  static void CreateRegExpCEntryStub();
+
   static void CreateFixedStubs();
 
   static Object* CreateOddball(Map* map,
index bc8107633e4fd0b363bc34050b6e240629b700e1..7af4e89e06e7cc4a8e4e64d3d77699c3520d3abd 100644 (file)
@@ -102,6 +102,7 @@ RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(
       success_label_(),
       backtrack_label_(),
       exit_label_() {
+  ASSERT_EQ(0, registers_to_save % 2);
   __ jmp(&entry_label_);   // We'll write the entry code later.
   __ bind(&start_label_);  // And then continue from here.
 }
@@ -337,8 +338,9 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
     __ add(edx, Operand(esi));
     __ mov(Operand(esp, 0 * kPointerSize), edx);
 
-    Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16);
-    CallCFunction(function_address, argument_count);
+    ExternalReference compare =
+        ExternalReference::re_case_insensitive_compare_uc16();
+    CallCFunction(compare, argument_count);
     // Pop original values before reacting on result value.
     __ pop(ebx);
     __ pop(backtrack_stackpointer());
@@ -745,7 +747,8 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
     __ lea(eax, Operand(ebp, kStackHighEnd));
     __ mov(Operand(esp, 1 * kPointerSize), eax);
     __ mov(Operand(esp, 0 * kPointerSize), backtrack_stackpointer());
-    CallCFunction(FUNCTION_ADDR(&GrowStack), num_arguments);
+    ExternalReference grow_stack = ExternalReference::re_grow_stack();
+    CallCFunction(grow_stack, num_arguments);
     // If return NULL, we have failed to grow the stack, and
     // must exit with a stack-overflow exception.
     __ or_(eax, Operand(eax));
@@ -817,7 +820,9 @@ void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
                                                     int characters) {
   ASSERT(cp_offset >= -1);      // ^ and \b can look behind one character.
   ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
-  CheckPosition(cp_offset + characters - 1, on_end_of_input);
+  if (check_bounds) {
+    CheckPosition(cp_offset + characters - 1, on_end_of_input);
+  }
   LoadCurrentCharacterUnchecked(cp_offset, characters);
 }
 
@@ -913,7 +918,9 @@ void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) {
   // Next address on the stack (will be address of return address).
   __ lea(eax, Operand(esp, -kPointerSize));
   __ mov(Operand(esp, 0 * kPointerSize), eax);
-  CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments);
+  ExternalReference check_stack_guard =
+      ExternalReference::re_check_stack_guard_state();
+  CallCFunction(check_stack_guard, num_arguments);
 }
 
 
@@ -996,22 +1003,6 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
 }
 
 
-Address RegExpMacroAssemblerIA32::GrowStack(Address stack_pointer,
-                                            Address* stack_base) {
-  size_t size = RegExpStack::stack_capacity();
-  Address old_stack_base = RegExpStack::stack_base();
-  ASSERT(old_stack_base == *stack_base);
-  ASSERT(stack_pointer <= old_stack_base);
-  ASSERT(static_cast<size_t>(old_stack_base - stack_pointer) <= size);
-  Address new_stack_base = RegExpStack::EnsureCapacity(size * 2);
-  if (new_stack_base == NULL) {
-    return NULL;
-  }
-  *stack_base = new_stack_base;
-  return new_stack_base - (old_stack_base - stack_pointer);
-}
-
-
 Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
   ASSERT(register_index < (1<<30));
   if (num_registers_ <= register_index) {
@@ -1135,9 +1126,9 @@ void RegExpMacroAssemblerIA32::FrameAlign(int num_arguments, Register scratch) {
 }
 
 
-void RegExpMacroAssemblerIA32::CallCFunction(Address function_address,
+void RegExpMacroAssemblerIA32::CallCFunction(ExternalReference function,
                                              int num_arguments) {
-  __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(function_address)));
+  __ mov(Operand(eax), Immediate(function));
   __ call(Operand(eax));
   if (OS::ActivationFrameAlignment() != 0) {
     __ mov(esp, Operand(esp, num_arguments * kPointerSize));
@@ -1172,6 +1163,10 @@ void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset,
 }
 
 
+void RegExpCEntryStub::Generate(MacroAssembler* masm_) {
+  __ int3();  // Unused on ia32.
+}
+
 #undef __
 
 #endif  // V8_NATIVE_REGEXP
index d11439299cbf322934a9ab5625e239293640da61..5ffd46275310b3993d9ae2bad4eaabbc8bf8c7c3 100644 (file)
@@ -107,6 +107,13 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler {
   virtual void ClearRegisters(int reg_from, int reg_to);
   virtual void WriteStackPointerToRegister(int reg);
 
+  // Called from RegExp if the stack-guard is triggered.
+  // If the code object is relocated, the return address is fixed before
+  // returning.
+  static int CheckStackGuardState(Address* return_address,
+                                  Code* re_code,
+                                  Address re_frame);
+
  private:
   // Offsets from ebp of function parameters and stored registers.
   static const int kFramePointer = 0;
@@ -144,23 +151,9 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler {
   // Check whether we are exceeding the stack limit on the backtrack stack.
   void CheckStackLimit();
 
-  // Called from RegExp if the stack-guard is triggered.
-  // If the code object is relocated, the return address is fixed before
-  // returning.
-  static int CheckStackGuardState(Address* return_address,
-                                  Code* re_code,
-                                  Address re_frame);
-
   // Generate a call to CheckStackGuardState.
   void CallCheckStackGuardState(Register scratch);
 
-  // Called from RegExp if the backtrack stack limit is hit.
-  // Tries to expand the stack. Returns the new stack-pointer if
-  // successful, and updates the stack_top address, or returns 0 if unable
-  // to grow the stack.
-  // This function must not trigger a garbage collection.
-  static Address GrowStack(Address stack_pointer, Address* stack_top);
-
   // The ebp-relative location of a regexp register.
   Operand register_location(int register_index);
 
@@ -209,7 +202,7 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler {
   // by FrameAlign. The called function is not allowed to trigger a garbage
   // collection, since that might move the code and invalidate the return
   // address (unless this is somehow accounted for).
-  inline void CallCFunction(Address function_address, int num_arguments);
+  inline void CallCFunction(ExternalReference function, int num_arguments);
 
   MacroAssembler* masm_;
 
index 4d02c03ab61e4cf428f1dabe0050165f30b122dc..3bed2681f8d785213991f148ceecc944130df413 100644 (file)
@@ -44,4 +44,9 @@
   (reinterpret_cast<uintptr_t>(this) >= limit ? \
       reinterpret_cast<uintptr_t>(this) - limit : 0)
 
+// Call the generated regexp code directly. The entry function pointer should
+// expect seven int/pointer sized arguments and return an int.
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
+  entry(p0, p1, p2, p3, p4, p5, p6)
+
 #endif  // V8_IA32_SIMULATOR_IA32_H_
index 06208aa50aebda4d9170781d220dac084b98cb24..40df777c8c7fa4075de37b973e93211c89ad04c9 100644 (file)
@@ -51,6 +51,7 @@
 #include "x64/macro-assembler-x64.h"
 #include "x64/regexp-macro-assembler-x64.h"
 #elif V8_TARGET_ARCH_ARM
+#include "arm/macro-assembler-arm.h"
 #include "arm/regexp-macro-assembler-arm.h"
 #else
 #error Unsupported target architecture.
@@ -419,9 +420,7 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
   Handle<FixedArray> regexp(FixedArray::cast(jsregexp->data()));
 
 #ifdef V8_NATIVE_REGEXP
-#ifdef V8_TARGET_ARCH_ARM
-  UNIMPLEMENTED();
-#else  // Native regexp supported.
+
   OffsetsVector captures(number_of_capture_registers);
   int* captures_vector = captures.vector();
   NativeRegExpMacroAssembler::Result res;
@@ -455,9 +454,9 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
     SetCapture(*array, i, captures_vector[i]);
     SetCapture(*array, i + 1, captures_vector[i + 1]);
   }
-#endif  // Native regexp supported.
 
 #else  // ! V8_NATIVE_REGEXP
+
   bool is_ascii = subject->IsAsciiRepresentation();
   if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) {
     return Handle<Object>::null();
@@ -487,6 +486,7 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
     SetCapture(*array, i, register_vector[i]);
     SetCapture(*array, i + 1, register_vector[i + 1]);
   }
+
 #endif  // V8_NATIVE_REGEXP
 
   SetLastCaptureCount(*array, number_of_capture_registers);
@@ -1723,6 +1723,8 @@ bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler,
   GetQuickCheckDetails(details, compiler, 0, trace->at_start() == Trace::FALSE);
   if (details->cannot_match()) return false;
   if (!details->Rationalize(compiler->ascii())) return false;
+  if (details->characters() > 1 &&
+      !compiler->macro_assembler()->CanReadUnaligned()) return false;
   uint32_t mask = details->mask();
   uint32_t value = details->value();
 
@@ -2522,20 +2524,20 @@ void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
 
 int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler) {
   int preload_characters = EatsAtLeast(4, 0);
-#ifdef V8_HOST_CAN_READ_UNALIGNED
-  bool ascii = compiler->ascii();
-  if (ascii) {
-    if (preload_characters > 4) preload_characters = 4;
-    // We can't preload 3 characters because there is no machine instruction
-    // to do that.  We can't just load 4 because we could be reading
-    // beyond the end of the string, which could cause a memory fault.
-    if (preload_characters == 3) preload_characters = 2;
+  if (compiler->macro_assembler()->CanReadUnaligned()) {
+    bool ascii = compiler->ascii();
+    if (ascii) {
+      if (preload_characters > 4) preload_characters = 4;
+      // We can't preload 3 characters because there is no machine instruction
+      // to do that.  We can't just load 4 because we could be reading
+      // beyond the end of the string, which could cause a memory fault.
+      if (preload_characters == 3) preload_characters = 2;
+    } else {
+      if (preload_characters > 2) preload_characters = 2;
+    }
   } else {
-    if (preload_characters > 2) preload_characters = 2;
+    if (preload_characters > 1) preload_characters = 1;
   }
-#else
-  if (preload_characters > 1) preload_characters = 1;
-#endif
   return preload_characters;
 }
 
@@ -4470,16 +4472,12 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data,
       is_ascii ? NativeRegExpMacroAssembler::ASCII
                : NativeRegExpMacroAssembler::UC16;
 
-#ifdef V8_TARGET_ARCH_IA32
-  RegExpMacroAssemblerIA32 macro_assembler(mode,
-                                           (data->capture_count + 1) * 2);
-#endif
-#ifdef V8_TARGET_ARCH_X64
-  RegExpMacroAssemblerX64 macro_assembler(mode,
-                                          (data->capture_count + 1) * 2);
-#endif
-#ifdef V8_TARGET_ARCH_ARM
-  UNIMPLEMENTED();
+#if V8_TARGET_ARCH_IA32
+  RegExpMacroAssemblerIA32 macro_assembler(mode, (data->capture_count + 1) * 2);
+#elif V8_TARGET_ARCH_X64
+  RegExpMacroAssemblerX64 macro_assembler(mode, (data->capture_count + 1) * 2);
+#elif V8_TARGET_ARCH_ARM
+  RegExpMacroAssemblerARM macro_assembler(mode, (data->capture_count + 1) * 2);
 #endif
 
 #else  // ! V8_NATIVE_REGEXP
index 5074f210a0bf24a298bb4544bbc2a5ef0e7b63c6..b487468effa7a5d11259962476cbbc9368a6dfb1 100644 (file)
@@ -38,6 +38,7 @@
 namespace v8 {
 namespace internal {
 
+#ifndef V8_NATIVE_REGEXP
 
 void RegExpMacroAssemblerIrregexp::Emit(uint32_t byte,
                                         uint32_t twenty_four_bits) {
@@ -70,6 +71,7 @@ void RegExpMacroAssemblerIrregexp::Emit32(uint32_t word) {
   pc_ += 4;
 }
 
+#endif  // ! V8_NATIVE_REGEXP
 
 } }  // namespace v8::internal
 
index 21b622ef052c8ef29102b6814668cc96aad60b8a..f9c7eeee01401e406228a63954faf791512772e6 100644 (file)
@@ -36,6 +36,7 @@
 namespace v8 {
 namespace internal {
 
+#ifndef V8_NATIVE_REGEXP
 
 RegExpMacroAssemblerIrregexp::RegExpMacroAssemblerIrregexp(Vector<byte> buffer)
     : buffer_(buffer),
@@ -458,5 +459,6 @@ void RegExpMacroAssemblerIrregexp::Expand() {
   }
 }
 
+#endif  // !V8_NATIVE_REGEXP
 
 } }  // namespace v8::internal
index dd64e7ae834c6a4c5b2b2d40d21bd9e5edada259..642a28390744b8df996fab7d0cfd93cbc48b1293 100644 (file)
@@ -31,6 +31,7 @@
 namespace v8 {
 namespace internal {
 
+#ifndef V8_NATIVE_REGEXP
 
 class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
  public:
@@ -133,6 +134,8 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
   DISALLOW_IMPLICIT_CONSTRUCTORS(RegExpMacroAssemblerIrregexp);
 };
 
+#endif  // !V8_NATIVE_REGEXP
+
 } }  // namespace v8::internal
 
 #endif  // V8_REGEXP_MACRO_ASSEMBLER_IRREGEXP_H_
index 28434d7cab4a9061db9f87d108e6162551673c2d..28ca5f340902f746412fde11d85531c5e2fbb311 100644 (file)
@@ -37,7 +37,7 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
   explicit RegExpMacroAssemblerTracer(RegExpMacroAssembler* assembler);
   virtual ~RegExpMacroAssemblerTracer();
   virtual int stack_limit_slack() { return assembler_->stack_limit_slack(); }
-
+  virtual bool CanReadUnaligned() { return assembler_->CanReadUnaligned(); }
   virtual void AdvanceCurrentPosition(int by);  // Signed cp change.
   virtual void AdvanceRegister(int reg, int by);  // r[reg] += by.
   virtual void Backtrack();
index 7f830fe4855ec909e1975edb1ad732cdbdd05174..0d00ceec350a9dd39454081a1e3f52231403510b 100644 (file)
 #include "assembler.h"
 #include "regexp-stack.h"
 #include "regexp-macro-assembler.h"
+#if V8_TARGET_ARCH_ARM
+#include "arm/simulator-arm.h"
+#elif V8_TARGET_ARCH_IA32
+#include "ia32/simulator-ia32.h"
+#elif V8_TARGET_ARCH_X64
+#include "x64/simulator-x64.h"
+#endif
 
 namespace v8 {
 namespace internal {
@@ -42,6 +49,15 @@ RegExpMacroAssembler::~RegExpMacroAssembler() {
 }
 
 
+bool RegExpMacroAssembler::CanReadUnaligned() {
+#ifdef V8_HOST_CAN_READ_UNALIGNED
+  return true;
+#else
+  return false;
+#endif
+}
+
+
 #ifdef V8_NATIVE_REGEXP  // Avoid unused code, e.g., on ARM.
 
 NativeRegExpMacroAssembler::NativeRegExpMacroAssembler() {
@@ -51,6 +67,15 @@ NativeRegExpMacroAssembler::NativeRegExpMacroAssembler() {
 NativeRegExpMacroAssembler::~NativeRegExpMacroAssembler() {
 }
 
+
+bool NativeRegExpMacroAssembler::CanReadUnaligned() {
+#ifdef V8_TARGET_CAN_READ_UNALIGNED
+  return true;
+#else
+  return false;
+#endif
+}
+
 const byte* NativeRegExpMacroAssembler::StringCharacterPosition(
     String* subject,
     int start_index) {
@@ -162,13 +187,14 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Execute(
   RegExpStack stack;
   Address stack_base = RegExpStack::stack_base();
 
-  int result = matcher_func(input,
-                            start_offset,
-                            input_start,
-                            input_end,
-                            output,
-                            at_start_val,
-                            stack_base);
+  int result = CALL_GENERATED_REGEXP_CODE(matcher_func,
+                                          input,
+                                          start_offset,
+                                          input_start,
+                                          input_end,
+                                          output,
+                                          at_start_val,
+                                          stack_base);
   ASSERT(result <= SUCCESS);
   ASSERT(result >= RETRY);
 
@@ -213,5 +239,22 @@ int NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16(
   return 1;
 }
 
+
+Address NativeRegExpMacroAssembler::GrowStack(Address stack_pointer,
+                                              Address* stack_base) {
+  size_t size = RegExpStack::stack_capacity();
+  Address old_stack_base = RegExpStack::stack_base();
+  ASSERT(old_stack_base == *stack_base);
+  ASSERT(stack_pointer <= old_stack_base);
+  ASSERT(static_cast<size_t>(old_stack_base - stack_pointer) <= size);
+  Address new_stack_base = RegExpStack::EnsureCapacity(size * 2);
+  if (new_stack_base == NULL) {
+    return NULL;
+  }
+  *stack_base = new_stack_base;
+  intptr_t stack_content_size = old_stack_base - stack_pointer;
+  return new_stack_base - stack_content_size;
+}
+
 #endif  // V8_NATIVE_REGEXP
 } }  // namespace v8::internal
index e59082768aa0140e02df6ec6f91a6a9b5a51234f..26aab2c72ea21f8ce14972c28c490fba652b1ff1 100644 (file)
@@ -61,6 +61,7 @@ class RegExpMacroAssembler {
   // kCheckStackLimit flag to push operations (instead of kNoStackLimitCheck)
   // at least once for every stack_limit() pushes that are executed.
   virtual int stack_limit_slack() = 0;
+  virtual bool CanReadUnaligned();
   virtual void AdvanceCurrentPosition(int by) = 0;  // Signed cp change.
   virtual void AdvanceRegister(int reg, int by) = 0;  // r[reg] += by.
   // Continues execution from the position pushed on the top of the backtrack
@@ -182,6 +183,7 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
 
   NativeRegExpMacroAssembler();
   virtual ~NativeRegExpMacroAssembler();
+  virtual bool CanReadUnaligned();
 
   static Result Match(Handle<Code> regexp,
                       Handle<String> subject,
@@ -195,6 +197,13 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
                                         Address byte_offset2,
                                         size_t byte_length);
 
+  // Called from RegExp if the backtrack stack limit is hit.
+  // Tries to expand the stack. Returns the new stack-pointer if
+  // successful, and updates the stack_top address, or returns 0 if unable
+  // to grow the stack.
+  // This function must not trigger a garbage collection.
+  static Address GrowStack(Address stack_pointer, Address* stack_top);
+
   static const byte* StringCharacterPosition(String* subject, int start_index);
 
   static Result Execute(Code* code,
@@ -205,7 +214,25 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
                         int* output,
                         bool at_start);
 };
+
+
+// Enter C code from generated RegExp code in a way that allows
+// the C code to fix the return address in case of a GC.
+// Currently only needed on ARM.
+class RegExpCEntryStub: public CodeStub {
+ public:
+  RegExpCEntryStub() {}
+  virtual ~RegExpCEntryStub() {}
+  void Generate(MacroAssembler* masm);
+
+ private:
+  Major MajorKey() { return RegExpCEntry; }
+  int MinorKey() { return 0; }
+  const char* GetName() { return "RegExpCEntryStub"; }
+};
+
 #endif  // V8_NATIVE_REGEXP
+
 } }  // namespace v8::internal
 
 #endif  // V8_REGEXP_MACRO_ASSEMBLER_H_
index d2fd1e4fca8f1756235565c4e83d57f1cbd79a6d..8b647da1c33f4b1fe207707ce6f84e50c7890b2e 100644 (file)
@@ -734,6 +734,20 @@ void ExternalReferenceTable::PopulateTable() {
       UNCLASSIFIED,
       17,
       "compare_doubles");
+#ifdef V8_NATIVE_REGEXP
+  Add(ExternalReference::re_case_insensitive_compare_uc16().address(),
+      UNCLASSIFIED,
+      18,
+      "NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16()");
+  Add(ExternalReference::re_check_stack_guard_state().address(),
+      UNCLASSIFIED,
+      19,
+      "RegExpMacroAssembler*::CheckStackGuardState()");
+  Add(ExternalReference::re_grow_stack().address(),
+      UNCLASSIFIED,
+      20,
+      "NativeRegExpMacroAssembler::GrowStack()");
+#endif
 }
 
 
@@ -1118,6 +1132,11 @@ void Serializer::PutHeader() {
   writer_->PutC(FLAG_debug_serialization ? '1' : '0');
 #else
   writer_->PutC('0');
+#endif
+#ifdef V8_NATIVE_REGEXP
+  writer_->PutC('N');
+#else  // Interpreted regexp
+  writer_->PutC('I');
 #endif
   // Write sizes of paged memory spaces. Allocate extra space for the old
   // and code spaces, because objects in new space will be promoted to them.
@@ -1474,6 +1493,11 @@ void Deserializer::GetHeader() {
   // In release mode, don't attempt to read a snapshot containing
   // synchronization tags.
   if (reader_.GetC() != '0') FATAL("Snapshot contains synchronization tags.");
+#endif
+#ifdef V8_NATIVE_REGEXP
+  reader_.ExpectC('N');
+#else  // Interpreted regexp.
+  reader_.ExpectC('I');
 #endif
   // Ensure sufficient capacity in paged memory spaces to avoid growth
   // during deserialization.
index 4c6a84d6ef242bdd7429896c1a9d165a0ef2be8c..373f359496e054fc9dc4cfe18fad131a752f60f7 100644 (file)
@@ -39,6 +39,8 @@
 namespace v8 {
 namespace internal {
 
+#ifdef V8_NATIVE_REGEXP
+
 /*
  * This assembler uses the following register assignment convention
  * - rdx : currently loaded character(s) as ASCII or UC16. Must be loaded using
@@ -110,6 +112,7 @@ RegExpMacroAssemblerX64::RegExpMacroAssemblerX64(
       success_label_(),
       backtrack_label_(),
       exit_label_() {
+  ASSERT_EQ(0, registers_to_save % 2);
   __ jmp(&entry_label_);   // We'll write the entry code when we know more.
   __ bind(&start_label_);  // And then continue from here.
 }
@@ -350,8 +353,9 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
     // Set byte_length.
     __ movq(rdx, rbx);
 #endif
-    Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16);
-    CallCFunction(function_address, num_arguments);
+    ExternalReference compare =
+        ExternalReference::re_case_insensitive_compare_uc16();
+    CallCFunction(compare, num_arguments);
 
     // Restore original values before reacting on result value.
     __ Move(code_object_pointer(), masm_->CodeObject());
@@ -808,11 +812,12 @@ Handle<Object> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
     // First argument, backtrack stackpointer, is already in rcx.
     __ lea(rdx, Operand(rbp, kStackHighEnd));  // Second argument
 #else
-    // AMD64 ABI passes paremeters in rdi, rsi.
+    // AMD64 ABI passes parameters in rdi, rsi.
     __ movq(rdi, backtrack_stackpointer());   // First argument.
     __ lea(rsi, Operand(rbp, kStackHighEnd));  // Second argument.
 #endif
-    CallCFunction(FUNCTION_ADDR(&GrowStack), num_arguments);
+    ExternalReference grow_stack = ExternalReference::re_grow_stack();
+    CallCFunction(grow_stack, num_arguments);
     // If return NULL, we have failed to grow the stack, and
     // must exit with a stack-overflow exception.
     __ testq(rax, rax);
@@ -889,7 +894,9 @@ void RegExpMacroAssemblerX64::LoadCurrentCharacter(int cp_offset,
                                                    int characters) {
   ASSERT(cp_offset >= -1);      // ^ and \b can look behind one character.
   ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
-  CheckPosition(cp_offset + characters - 1, on_end_of_input);
+  if (check_bounds) {
+    CheckPosition(cp_offset + characters - 1, on_end_of_input);
+  }
   LoadCurrentCharacterUnchecked(cp_offset, characters);
 }
 
@@ -997,7 +1004,9 @@ void RegExpMacroAssemblerX64::CallCheckStackGuardState() {
   // return address).
   __ lea(rdi, Operand(rsp, -kPointerSize));
 #endif
-  CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments);
+  ExternalReference stack_check =
+      ExternalReference::re_check_stack_guard_state();
+  CallCFunction(stack_check, num_arguments);
 }
 
 
@@ -1080,23 +1089,6 @@ int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
 }
 
 
-Address RegExpMacroAssemblerX64::GrowStack(Address stack_pointer,
-                                           Address* stack_base) {
-  size_t size = RegExpStack::stack_capacity();
-  Address old_stack_base = RegExpStack::stack_base();
-  ASSERT(old_stack_base == *stack_base);
-  ASSERT(stack_pointer <= old_stack_base);
-  ASSERT(static_cast<size_t>(old_stack_base - stack_pointer) <= size);
-  Address new_stack_base = RegExpStack::EnsureCapacity(size * 2);
-  if (new_stack_base == NULL) {
-    return NULL;
-  }
-  *stack_base = new_stack_base;
-  intptr_t stack_content_size = old_stack_base - stack_pointer;
-  return new_stack_base - stack_content_size;
-}
-
-
 Operand RegExpMacroAssemblerX64::register_location(int register_index) {
   ASSERT(register_index < (1<<30));
   if (num_registers_ <= register_index) {
@@ -1256,17 +1248,16 @@ void RegExpMacroAssemblerX64::FrameAlign(int num_arguments) {
 }
 
 
-void RegExpMacroAssemblerX64::CallCFunction(Address function_address,
+void RegExpMacroAssemblerX64::CallCFunction(ExternalReference function,
                                             int num_arguments) {
-  // Don't compile regexps with serialization enabled. The addresses of the C++
-  // function being called isn't relocatable.
-  ASSERT(!Serializer::enabled());
-  __ movq(rax, reinterpret_cast<intptr_t>(function_address), RelocInfo::NONE);
+  __ movq(rax, function);
   __ call(rax);
   ASSERT(OS::ActivationFrameAlignment() != 0);
 #ifdef _WIN64
   __ movq(rsp, Operand(rsp, num_arguments * kPointerSize));
 #else
+  // All arguments passed in registers.
+  ASSERT(num_arguments <= 6);
   __ pop(rsp);
 #endif
 }
@@ -1297,5 +1288,12 @@ void RegExpMacroAssemblerX64::LoadCurrentCharacterUnchecked(int cp_offset,
 }
 
 
+void RegExpCEntryStub::Generate(MacroAssembler* masm_) {
+  __ int3();  // Unused on x64.
+}
+
 #undef __
+
+#endif  // V8_NATIVE_REGEXP
+
 }}  // namespace v8::internal
index a270bc18655e183ca5b14b1822a0a049b52b672d..ab9647704b32b92f6e09daca7892af249c4e5bb2 100644 (file)
@@ -31,6 +31,8 @@
 namespace v8 {
 namespace internal {
 
+#ifdef V8_NATIVE_REGEXP
+
 class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
  public:
   RegExpMacroAssemblerX64(Mode mode, int registers_to_save);
@@ -113,6 +115,13 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
                         int* output,
                         bool at_start);
 
+  // Called from RegExp if the stack-guard is triggered.
+  // If the code object is relocated, the return address is fixed before
+  // returning.
+  static int CheckStackGuardState(Address* return_address,
+                                  Code* re_code,
+                                  Address re_frame);
+
  private:
   // Offsets from rbp of function parameters and stored registers.
   static const int kFramePointer = 0;
@@ -181,23 +190,9 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
   // Check whether we are exceeding the stack limit on the backtrack stack.
   void CheckStackLimit();
 
-  // Called from RegExp if the stack-guard is triggered.
-  // If the code object is relocated, the return address is fixed before
-  // returning.
-  static int CheckStackGuardState(Address* return_address,
-                                  Code* re_code,
-                                  Address re_frame);
-
   // Generate a call to CheckStackGuardState.
   void CallCheckStackGuardState();
 
-  // Called from RegExp if the backtrack stack limit is hit.
-  // Tries to expand the stack. Returns the new stack-pointer if
-  // successful, and updates the stack_top address, or returns 0 if unable
-  // to grow the stack.
-  // This function must not trigger a garbage collection.
-  static Address GrowStack(Address stack_pointer, Address* stack_top);
-
   // The rbp-relative location of a regexp register.
   Operand register_location(int register_index);
 
@@ -264,7 +259,7 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
   // by FrameAlign. The called function is not allowed to trigger a garbage
   // collection, since that might move the code and invalidate the return
   // address (unless this is somehow accounted for by the called function).
-  inline void CallCFunction(Address function_address, int num_arguments);
+  inline void CallCFunction(ExternalReference function, int num_arguments);
 
   MacroAssembler* masm_;
 
@@ -290,6 +285,8 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
   Label stack_overflow_label_;
 };
 
+#endif  // V8_NATIVE_REGEXP
+
 }}  // namespace v8::internal
 
 #endif  // V8_X64_REGEXP_MACRO_ASSEMBLER_X64_H_
index 6b4d718f66edf9a7d6b294764eba0b355b74ef40..184c166bc0592a271320e7f51a851a8595fcb24d 100644 (file)
@@ -45,4 +45,9 @@
   (reinterpret_cast<uintptr_t>(this) >= limit ? \
       reinterpret_cast<uintptr_t>(this) - limit : 0)
 
+// Call the generated regexp code directly. The entry function pointer should
+// expect seven int/pointer sized arguments and return an int.
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
+  entry(p0, p1, p2, p3, p4, p5, p6)
+
 #endif  // V8_X64_SIMULATOR_X64_H_
index fe1621c2ab0aa11a4353d67160b38a55a567be0e..34f16395e2e7e6d80d0fe2fd2e496b5ea6928a27 100644 (file)
@@ -185,7 +185,7 @@ TEST(3) {
   Label L, C;
 
   __ mov(ip, Operand(sp));
-  __ stm(db_w, sp, r4.bit() | fp.bit() | sp.bit() | lr.bit());
+  __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
   __ sub(fp, ip, Operand(4));
   __ mov(r4, Operand(r0));
   __ ldr(r0, MemOperand(r4, OFFSET_OF(T, i)));
@@ -199,7 +199,7 @@ TEST(3) {
   __ add(r0, r2, Operand(r0));
   __ mov(r2, Operand(r2, ASR, 3));
   __ strh(r2, MemOperand(r4, OFFSET_OF(T, s)));
-  __ ldm(ia, sp, r4.bit() | fp.bit() | sp.bit() | pc.bit());
+  __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
 
   CodeDesc desc;
   assm.GetCode(&desc);
index 89c7868d838cef52f5b6b2ce752e0ba43a8662f1..81c220520480f4051de185cccc1922b8091a538d 100644 (file)
@@ -40,6 +40,7 @@
 #include "regexp-macro-assembler-irregexp.h"
 #ifdef V8_NATIVE_REGEXP
 #ifdef V8_TARGET_ARCH_ARM
+#include "arm/macro-assembler-arm.h"
 #include "arm/regexp-macro-assembler-arm.h"
 #endif
 #ifdef V8_TARGET_ARCH_X64
@@ -605,11 +606,12 @@ TEST(DispatchTableConstruction) {
 
 #ifdef V8_NATIVE_REGEXP
 
-#ifdef V8_TARGET_ARCH_IA32
+#if V8_TARGET_ARCH_IA32
 typedef RegExpMacroAssemblerIA32 ArchRegExpMacroAssembler;
-#endif
-#ifdef V8_TARGET_ARCH_X64
+#elif V8_TARGET_ARCH_X64
 typedef RegExpMacroAssemblerX64 ArchRegExpMacroAssembler;
+#elif V8_TARGET_ARCH_ARM
+typedef RegExpMacroAssemblerARM ArchRegExpMacroAssembler;
 #endif
 
 class ContextInitializer {
@@ -845,7 +847,7 @@ TEST(MacroAssemblerNativeBackReferenceASCII) {
   v8::V8::Initialize();
   ContextInitializer initializer;
 
-  ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 3);
+  ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 4);
 
   m.WriteCurrentPositionToRegister(0, 0);
   m.AdvanceCurrentPosition(2);
@@ -870,7 +872,7 @@ TEST(MacroAssemblerNativeBackReferenceASCII) {
   Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
   Address start_adr = seq_input->GetCharsAddress();
 
-  int output[3];
+  int output[4];
   NativeRegExpMacroAssembler::Result result =
       Execute(*code,
               *input,
@@ -884,6 +886,7 @@ TEST(MacroAssemblerNativeBackReferenceASCII) {
   CHECK_EQ(0, output[0]);
   CHECK_EQ(2, output[1]);
   CHECK_EQ(6, output[2]);
+  CHECK_EQ(-1, output[3]);
 }
 
 
@@ -891,7 +894,7 @@ TEST(MacroAssemblerNativeBackReferenceUC16) {
   v8::V8::Initialize();
   ContextInitializer initializer;
 
-  ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::UC16, 3);
+  ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::UC16, 4);
 
   m.WriteCurrentPositionToRegister(0, 0);
   m.AdvanceCurrentPosition(2);
@@ -918,7 +921,7 @@ TEST(MacroAssemblerNativeBackReferenceUC16) {
   Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
   Address start_adr = seq_input->GetCharsAddress();
 
-  int output[3];
+  int output[4];
   NativeRegExpMacroAssembler::Result result =
       Execute(*code,
                   *input,
@@ -932,6 +935,7 @@ TEST(MacroAssemblerNativeBackReferenceUC16) {
   CHECK_EQ(0, output[0]);
   CHECK_EQ(2, output[1]);
   CHECK_EQ(6, output[2]);
+  CHECK_EQ(-1, output[3]);
 }
 
 
@@ -1055,12 +1059,12 @@ TEST(MacroAssemblerNativeRegisters) {
   v8::V8::Initialize();
   ContextInitializer initializer;
 
-  ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 5);
+  ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 6);
 
   uc16 foo_chars[3] = {'f', 'o', 'o'};
   Vector<const uc16> foo(foo_chars, 3);
 
-  enum registers { out1, out2, out3, out4, out5, sp, loop_cnt };
+  enum registers { out1, out2, out3, out4, out5, out6, sp, loop_cnt };
   Label fail;
   Label backtrack;
   m.WriteCurrentPositionToRegister(out1, 0);  // Output: [0]
@@ -1114,7 +1118,7 @@ TEST(MacroAssemblerNativeRegisters) {
   m.GoTo(&loop3);
   m.Bind(&exit_loop3);
   m.PopCurrentPosition();
-  m.WriteCurrentPositionToRegister(out5, 0);  // [0,3,6,9,9]
+  m.WriteCurrentPositionToRegister(out5, 0);  // [0,3,6,9,9,-1]
 
   m.Succeed();
 
@@ -1132,15 +1136,15 @@ TEST(MacroAssemblerNativeRegisters) {
   Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
   Address start_adr = seq_input->GetCharsAddress();
 
-  int output[5];
+  int output[6];
   NativeRegExpMacroAssembler::Result result =
       Execute(*code,
-                  *input,
-                  0,
-                  start_adr,
-                  start_adr + input->length(),
-                  output,
-                  true);
+              *input,
+              0,
+              start_adr,
+              start_adr + input->length(),
+              output,
+              true);
 
   CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
   CHECK_EQ(0, output[0]);
@@ -1148,6 +1152,7 @@ TEST(MacroAssemblerNativeRegisters) {
   CHECK_EQ(6, output[2]);
   CHECK_EQ(9, output[3]);
   CHECK_EQ(9, output[4]);
+  CHECK_EQ(-1, output[5]);
 }
 
 
index 037efa70c182d9c0f521623aad4e00489b69cd31..1222ea9c9b481803c6f25edae69f7a2a27e35de4 100644 (file)
             '../../src/ia32/jump-target-ia32.cc',
             '../../src/ia32/macro-assembler-ia32.cc',
             '../../src/ia32/macro-assembler-ia32.h',
+            '../../src/ia32/regexp-macro-assembler-ia32.cc',
+            '../../src/ia32/regexp-macro-assembler-ia32.h',
             '../../src/ia32/register-allocator-ia32.cc',
             '../../src/ia32/stub-cache-ia32.cc',
             '../../src/ia32/virtual-frame-ia32.cc',
             '../../src/ia32/virtual-frame-ia32.h',
           ],
         }],
-        ['target_arch=="ia32" and v8_regexp=="native"', {
-          'sources': [
-            '../../src/ia32/regexp-macro-assembler-ia32.cc',
-            '../../src/ia32/regexp-macro-assembler-ia32.h',
-          ],
-        }],
         ['target_arch=="x64"', {
           'include_dirs+': [
             '../../src/x64',
             '../../src/x64/jump-target-x64.cc',
             '../../src/x64/macro-assembler-x64.cc',
             '../../src/x64/macro-assembler-x64.h',
+            '../../src/x64/regexp-macro-assembler-x64.cc',
+            '../../src/x64/regexp-macro-assembler-x64.h',
             '../../src/x64/register-allocator-x64.cc',
             '../../src/x64/stub-cache-x64.cc',
             '../../src/x64/virtual-frame-x64.cc',
             '../../src/x64/virtual-frame-x64.h',
           ],
         }],
-        ['target_arch=="x64" and v8_regexp=="native"', {
-          'sources': [
-            '../../src/x64/regexp-macro-assembler-x64.cc',
-            '../../src/x64/regexp-macro-assembler-x64.h',
-          ],
-        }],
         ['OS=="linux"', {
             'link_settings': {
               'libraries': [