Fixes (last?) bugs in regexp-ia32 core functionality. All tests run!
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 1 Dec 2008 09:57:14 +0000 (09:57 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 1 Dec 2008 09:57:14 +0000 (09:57 +0000)
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@873 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/assembler-ia32.cc
src/assembler-ia32.h
src/jsregexp.cc
src/regexp-macro-assembler-ia32.cc
src/regexp-macro-assembler-ia32.h
src/regexp-macro-assembler-tracer.cc
test/cctest/test-regexp.cc

index 4c5ef16b1c4a98cafbd1a8f2a3f1996a5fa1424c..c7571e31354ccf75801d676364cecf7566aac883 100644 (file)
@@ -840,6 +840,26 @@ void Assembler::and_(const Operand& dst, Register src) {
 }
 
 
+void Assembler::cmpb(const Operand& op, int8_t imm8) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x80);
+  emit_operand(edi, op);  // edi == 7
+  EMIT(imm8);
+}
+
+
+void Assembler::cmpw(const Operand& op, Immediate imm16) {
+  ASSERT(imm16.is_int16());
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x66);
+  EMIT(0x81);
+  emit_operand(edi, op);
+  emit_w(imm16);
+}
+
+
 void Assembler::cmp(Register reg, int32_t imm32) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -877,12 +897,13 @@ void Assembler::rep_cmpsb() {
   EMIT(0xA6);  // CMPSB
 }
 
-void Assembler::rep_cmpsl() {
+void Assembler::rep_cmpsw() {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
   EMIT(0xFC);  // CLD to ensure forward operation
   EMIT(0xF3);  // REP
-  EMIT(0xA7);  // CMPSW
+  EMIT(0x66);  // Operand size overide.
+  EMIT(0xA7);  // CMPS
 }
 
 
index 8e330d181cf720628fad2decce78128a75887814..17c6b82d600fd41258127426b4d21c9eb1364eb4 100644 (file)
@@ -189,6 +189,9 @@ class Immediate BASE_EMBEDDED {
   bool is_int8() const {
     return -128 <= x_ && x_ < 128 && rmode_ == RelocInfo::NONE;
   }
+  bool is_int16() const {
+    return -32768 <= x_ && x_ < 32768 && rmode_ == RelocInfo::NONE;
+  }
 
  private:
   int x_;
@@ -493,13 +496,15 @@ class Assembler : public Malloced {
   void and_(const Operand& src, Register dst);
   void and_(const Operand& dst, const Immediate& x);
 
+  void cmpb(const Operand& op, int8_t imm8);
+  void cmpw(const Operand& op, Immediate imm16);
   void cmp(Register reg, int32_t imm32);
   void cmp(Register reg, Handle<Object> handle);
   void cmp(Register reg, const Operand& op);
   void cmp(const Operand& op, const Immediate& imm);
 
   void rep_cmpsb();
-  void rep_cmpsl();
+  void rep_cmpsw();
 
   void dec_b(Register dst);
 
index 43148a9b0e75211fa72d5f4b3c9a77c27454cded..be767bff71f03acec1bbbb496ec409a9fde62abf 100644 (file)
@@ -513,12 +513,12 @@ Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<JSRegExp> regexp,
       int start_offset = string_offset + previous_index * sizeof(uc16);
       int end_offset =
           string_offset + two_byte_subject->length() * sizeof(uc16);
-      typedef bool testfunc(String**, int, int, int*);
-      testfunc* test = FUNCTION_CAST<testfunc*>(code->entry());
-      rc = test(two_byte_subject.location(),
-                start_offset,
-                end_offset,
-                offsets_vector);
+      rc = RegExpMacroAssemblerIA32::Execute(code,
+                                             two_byte_subject.location(),
+                                             start_offset,
+                                             end_offset,
+                                             offsets_vector,
+                                             previous_index == 0);
       if (rc) {
         // Capture values are relative to start_offset only.
         for (int i = 0; i < offsets_vector_length; i++) {
index cc0a500326e9dd8e6b55307494c728eacea1331d..e58323f11fce7e2f7686259677028c0f0304807c 100644 (file)
@@ -51,6 +51,7 @@ namespace v8 { namespace internal {
  *
  * Each call to a public method should retain this convention.
  * The stack will have the following structure:
+ *       - at_start           (if 1, start at start of string, if 0, don't)
  *       - int* capture_array (int[num_saved_registers_], for output).
  *       - end of input       (index of end of string, relative to *string_base)
  *       - start of input     (index of first character in string, relative
@@ -59,6 +60,7 @@ namespace v8 { namespace internal {
  *       - return address
  *       - backup of esi
  *       - backup of edi
+ *       - backup of ebx
  * ebp-> - old ebp
  *       - register 0  ebp[-4]  (Only positions must be stored in the first
  *       - register 1  ebp[-8]   num_saved_registers_ registers)
@@ -73,7 +75,8 @@ namespace v8 { namespace internal {
  * bool (*match)(String** string_base,
  *               int start_offset,
  *               int end_offset,
- *               int* capture_output_array)
+ *               int* capture_output_array,
+ *               bool at_start)
  */
 
 #define __ masm_->
@@ -135,7 +138,7 @@ void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start,
                                            Label* bitmap,
                                            Label* on_zero) {
   UNREACHABLE();
-  ReadCurrentChar(eax);
+  __ mov(eax, current_character());
   __ sub(Operand(eax), Immediate(start));
   __ cmp(eax, 64);  // FIXME: 64 = length_of_bitmap_in_bits.
   BranchOrBacktrack(greater_equal, on_zero);
@@ -151,24 +154,29 @@ void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start,
 
 
 void RegExpMacroAssemblerIA32::CheckCharacter(uc16 c, Label* on_equal) {
-  __ cmp(edx, c);
+  __ cmp(current_character(), c);
   BranchOrBacktrack(equal, on_equal);
 }
 
 
 void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
-  __ cmp(edx, limit);
+  __ cmp(current_character(), limit);
   BranchOrBacktrack(greater, on_greater);
 }
 
 
 void RegExpMacroAssemblerIA32::CheckNotAtStart(Label* on_not_at_start) {
-  UNIMPLEMENTED();
+  __ cmp(Operand(ebp, kAtStart), Immediate(0));
+  BranchOrBacktrack(equal, on_not_at_start);
+  __ mov(eax, Operand(ebp, kInputEndOffset));
+  __ add(eax, Operand(edi));
+  __ cmp(eax, Operand(ebp, kInputStartOffset));
+  BranchOrBacktrack(not_equal, on_not_at_start);
 }
 
 
 void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) {
-  __ cmp(edx, limit);
+  __ cmp(current_character(), limit);
   BranchOrBacktrack(less, on_less);
 }
 
@@ -178,9 +186,23 @@ void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
                                                Label* on_failure) {
   int byte_length = str.length() * char_size();
   int byte_offset = cp_offset * char_size();
-  __ mov(ebx, edi);
-  __ add(Operand(ebx), Immediate(byte_offset + byte_length));
-  BranchOrBacktrack(greater_equal, on_failure);
+  __ cmp(Operand(edi), Immediate(-(byte_offset + byte_length)));
+  BranchOrBacktrack(greater, on_failure);
+
+  if (str.length() <= kMaxInlineStringTests) {
+    for (int i = 0; i < str.length(); i++) {
+      if (mode_ == ASCII) {
+        __ cmpb(Operand(esi, edi, times_1, byte_offset + i),
+                static_cast<int8_t>(str[i]));
+      } else {
+        ASSERT(mode_ == UC16);
+        __ cmpw(Operand(esi, edi, times_1, byte_offset + i * sizeof(uc16)),
+                Immediate(str[i]));
+      }
+      __ j(not_equal, on_failure);
+    }
+    return;
+  }
 
   ArraySlice constant_buffer = constants_.GetBuffer(str.length(), char_size());
   if (mode_ == ASCII) {
@@ -197,8 +219,13 @@ void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
   __ mov(ebx, esi);
   __ lea(edi, Operand(esi, edi, times_1, byte_offset));
   LoadConstantBufferAddress(esi, &constant_buffer);
-  __ mov(ecx, str.length() * char_size());
-  __ rep_cmpsb();
+  __ mov(ecx, str.length());
+  if (char_size() == 1) {
+    __ rep_cmpsb();
+  } else {
+    ASSERT(char_size() == 2);
+    __ rep_cmpsw();
+  }
   __ mov(esi, ebx);
   __ mov(edi, eax);
   BranchOrBacktrack(not_equal, on_failure);
@@ -214,7 +241,16 @@ void RegExpMacroAssemblerIA32::CheckCurrentPosition(int register_index,
 
 void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
     int start_reg, Label* on_no_match) {
-  UNIMPLEMENTED();
+  Label fallthrough;
+  __ mov(eax, register_location(start_reg));
+  __ mov(ecx, register_location(start_reg + 1));
+  __ sub(ecx, Operand(eax));  // Length to check.
+  __ j(less, on_no_match);
+  __ j(equal, &fallthrough);
+
+  UNIMPLEMENTED();  // TODO(lrn): Call runtime function to do test.
+
+  __ bind(&fallthrough);
 }
 
 
@@ -224,15 +260,16 @@ void RegExpMacroAssemblerIA32::CheckNotBackReference(
   __ mov(eax, register_location(start_reg));
   __ mov(ecx, register_location(start_reg + 1));
   __ sub(ecx, Operand(eax));  // Length to check.
-  __ j(equal, &fallthrough);  // Covers the case where it's not bound (-1,-1).
+  __ j(less, on_no_match);
+  __ j(equal, &fallthrough);
+  // check that there are sufficient characters left in the input
+  __ mov(ebx, edi);
+  __ add(ebx, Operand(ecx));
+  __ j(greater, on_no_match);
   __ mov(ebx, Operand(edi));
   __ push(esi);
   __ add(edi, Operand(esi));
   __ add(esi, Operand(eax));
-  if (char_size() > 0) {
-    ASSERT(char_size() == 2);
-    __ add(ecx, Operand(ecx));
-  }
   __ rep_cmpsb();
   __ pop(esi);
   __ mov(edi, Operand(ebx));
@@ -245,14 +282,13 @@ void RegExpMacroAssemblerIA32::CheckNotRegistersEqual(int reg1,
                                                       int reg2,
                                                       Label* on_not_equal) {
   __ mov(eax, register_location(reg1));
-  __ mov(ecx, register_location(reg2));
-  __ cmp(ecx, Operand(eax));
+  __ cmp(eax, register_location(reg2));
   BranchOrBacktrack(not_equal, on_not_equal);
 }
 
 
 void RegExpMacroAssemblerIA32::CheckNotCharacter(uc16 c, Label* on_not_equal) {
-  __ cmp(edx, c);
+  __ cmp(current_character(), c);
   BranchOrBacktrack(not_equal, on_not_equal);
 }
 
@@ -260,7 +296,7 @@ void RegExpMacroAssemblerIA32::CheckNotCharacter(uc16 c, Label* on_not_equal) {
 void RegExpMacroAssemblerIA32::CheckNotCharacterAfterOr(uc16 c,
                                                         uc16 mask,
                                                         Label* on_not_equal) {
-  __ mov(eax, Operand(edx));
+  __ mov(eax, current_character());
   __ or_(eax, mask);
   __ cmp(eax, c);
   BranchOrBacktrack(not_equal, on_not_equal);
@@ -271,7 +307,7 @@ void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusOr(
     uc16 c,
     uc16 mask,
     Label* on_not_equal) {
-  __ lea(eax, Operand(edx, -mask));
+  __ lea(eax, Operand(current_character(), -mask));
   __ or_(eax, mask);
   __ cmp(eax, c);
   BranchOrBacktrack(not_equal, on_not_equal);
@@ -282,7 +318,8 @@ void RegExpMacroAssemblerIA32::DispatchHalfNibbleMap(
     uc16 start,
     Label* half_nibble_map,
     const Vector<Label*>& destinations) {
-  ReadCurrentChar(eax);
+  UNIMPLEMENTED();
+  __ mov(eax, current_character());
   __ sub(Operand(eax), Immediate(start));
 
   __ mov(ecx, eax);
@@ -318,8 +355,10 @@ void RegExpMacroAssemblerIA32::DispatchByteMap(
     uc16 start,
     Label* byte_map,
     const Vector<Label*>& destinations) {
+  UNIMPLEMENTED();
+
   Label fallthrough;
-  ReadCurrentChar(eax);
+  __ mov(eax, current_character());
   __ sub(Operand(eax), Immediate(start));
   __ cmp(eax, 64);  // FIXME: 64 = size of map. Found somehow??
   __ j(greater_equal, &fallthrough);
@@ -335,10 +374,10 @@ void RegExpMacroAssemblerIA32::DispatchHighByteMap(
     byte start,
     Label* byte_map,
     const Vector<Label*>& destinations) {
-  UNREACHABLE();
+  UNIMPLEMENTED();
 
   Label fallthrough;
-  ReadCurrentChar(eax);
+  __ mov(eax, current_character());
   __ shr(eax, 8);
   __ sub(Operand(eax), Immediate(start));
   __ cmp(eax, destinations.length() - start);
@@ -350,7 +389,7 @@ void RegExpMacroAssemblerIA32::DispatchHighByteMap(
 
 
 void RegExpMacroAssemblerIA32::EmitOrLink(Label* label) {
-  UNREACHABLE();  // Has no use.
+  UNIMPLEMENTED();  // Has no use.
 }
 
 
@@ -395,9 +434,19 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode() {
     __ inc(ecx);
     __ j(not_equal, &init_loop);
   }
+  // Load previous char as initial value of current-character.
+  Label at_start;
+  __ cmp(Operand(ebp, kAtStart), Immediate(0));
+  __ j(not_equal, &at_start);
+  LoadCurrentCharToRegister(-1);  // Load previous char.
+  __ jmp(&start_label_);
+  __ bind(&at_start);
+  __ mov(current_character(), '\n');
   __ jmp(&start_label_);
 
+
   // Exit code:
+  // Success
   __ bind(&success_label_);
   if (num_saved_registers_ > 0) {
     // copy captures to output
@@ -416,6 +465,7 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode() {
   }
   __ mov(eax, Immediate(1));
 
+  // Exit and return eax
   __ bind(&exit_label_);
   __ leave();
   __ pop(ebx);
@@ -439,7 +489,6 @@ void RegExpMacroAssemblerIA32::GoTo(Label* to) {
 }
 
 
-
 void RegExpMacroAssemblerIA32::IfRegisterGE(int reg,
                                             int comparand,
                                             Label* if_ge) {
@@ -448,7 +497,6 @@ void RegExpMacroAssemblerIA32::IfRegisterGE(int reg,
 }
 
 
-
 void RegExpMacroAssemblerIA32::IfRegisterLT(int reg,
                                             int comparand,
                                             Label* if_lt) {
@@ -457,21 +505,19 @@ void RegExpMacroAssemblerIA32::IfRegisterLT(int reg,
 }
 
 
-
 RegExpMacroAssembler::IrregexpImplementation
     RegExpMacroAssemblerIA32::Implementation() {
   return kIA32Implementation;
 }
 
 
-
 void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
                                                     Label* on_end_of_input) {
   ASSERT(cp_offset >= 0);
   ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
   __ cmp(edi, -cp_offset * char_size());
   BranchOrBacktrack(greater_equal, on_end_of_input);
-  ReadChar(edx, cp_offset);
+  LoadCurrentCharToRegister(cp_offset);
 }
 
 
@@ -481,7 +527,6 @@ void RegExpMacroAssemblerIA32::PopCurrentPosition() {
 
 
 void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
-  RecordRegister(register_index);
   __ pop(register_location(register_index));
 }
 
@@ -514,7 +559,6 @@ void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) {
 
 void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) {
   ASSERT(register_index >= num_saved_registers_);  // Reserved for positions!
-  RecordRegister(register_index);
   __ mov(register_location(register_index), Immediate(to));
 }
 
@@ -524,10 +568,8 @@ void RegExpMacroAssemblerIA32::Succeed() {
 }
 
 
-void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(
-    int register_index) {
-  RecordRegister(register_index);
-  __ mov(register_location(register_index), edi);
+void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg) {
+  __ mov(register_location(reg), edi);
 }
 
 void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
@@ -537,13 +579,20 @@ void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
 
 // Private methods:
 
-Operand RegExpMacroAssemblerIA32::register_location(
-    int register_index) {
+Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
   ASSERT(register_index < (1<<30));
+  if (num_registers_ <= register_index) {
+    num_registers_ = register_index + 1;
+  }
   return Operand(ebp, -(register_index + 1) * kPointerSize);
 }
 
 
+Register RegExpMacroAssemblerIA32::current_character() {
+  return edx;
+}
+
+
 size_t RegExpMacroAssemblerIA32::char_size() {
   return static_cast<size_t>(mode_);
 }
@@ -570,22 +619,6 @@ void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
 }
 
 
-void RegExpMacroAssemblerIA32::Canonicalize(Register reg) {
-  if (mode_ == ASCII) {
-    Label end;
-    __ cmp(Operand(reg), Immediate('a'));
-    __ j(below, &end);
-    __ cmp(Operand(reg), Immediate('z'));
-    __ j(above, &end);
-    __ sub(Operand(reg), Immediate('a' - 'A'));
-    __ bind(&end);
-    return;
-  }
-  ASSERT(mode_ == UC16);
-  // TODO(lrn): Use some tables.
-}
-
-
 void RegExpMacroAssemblerIA32::CheckStackLimit() {
   if (FLAG_check_stack) {
     // Check for preemption first.
@@ -624,25 +657,14 @@ void RegExpMacroAssemblerIA32::CheckStackLimit() {
 }
 
 
-void RegExpMacroAssemblerIA32::RecordRegister(int register_index) {
-  if (register_index >= num_registers_) {
-    num_registers_ = register_index + 1;
-  }
-}
-
-
-void RegExpMacroAssemblerIA32::ReadChar(Register destination, int offset) {
+void RegExpMacroAssemblerIA32::LoadCurrentCharToRegister(int cp_offset) {
   if (mode_ == ASCII) {
-    __ movzx_b(destination, Operand(esi, edi, times_1, offset));
+    __ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset));
     return;
   }
   ASSERT(mode_ == UC16);
-  __ movzx_w(destination, Operand(esi, edi, times_1, offset * 2));
-}
-
-
-void RegExpMacroAssemblerIA32::ReadCurrentChar(Register destination) {
-  __ mov(destination, edx);
+  __ movzx_w(current_character(),
+             Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
 }
 
 
index de653d57044ef83441fa48f7943ca2733d5d2015..d303910f16ad065ff39c8a689c7a45ee73ad9f23 100644 (file)
@@ -88,6 +88,19 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
   virtual void WriteCurrentPositionToRegister(int reg);
   virtual void WriteStackPointerToRegister(int reg);
 
+  template <typename T>
+  static inline bool Execute(Code* code,
+                             T** input,
+                             int start_offset,
+                             int end_offset,
+                             int* output,
+                             bool at_start) {
+    typedef bool (*matcher)(T**, int, int, int*, int);
+    matcher matcher_func = FUNCTION_CAST<matcher>(code->entry());
+    int at_start_val = at_start ? 1 : 0;
+    return matcher_func(input, start_offset, end_offset, output, at_start_val);
+  }
+
  private:
   // Offsets from ebp of arguments to function.
   static const int kBackup_ebx = sizeof(uint32_t);
@@ -98,6 +111,7 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
   static const int kInputStartOffset = kInputBuffer + sizeof(uint32_t);
   static const int kInputEndOffset = kInputStartOffset + sizeof(uint32_t);
   static const int kRegisterOutput = kInputEndOffset + sizeof(uint32_t);
+  static const int kAtStart = kRegisterOutput + sizeof(uint32_t);
 
   // Initial size of code buffer.
   static const size_t kRegExpCodeSize = 1024;
@@ -111,32 +125,25 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
   // The ebp-relative location of a regexp register.
   Operand register_location(int register_index);
 
+  // The register containing the current character after LoadCurrentCharacter.
+  Register current_character();
+
   // Byte size of chars in the string to match (decided by the Mode argument)
   size_t char_size();
 
-  // Records that a register is used. At the end, we need the number of
-  // registers used.
-  void RecordRegister(int register_index);
-
   // Equivalent to a conditional branch to the label, unless the label
   // is NULL, in which case it is a conditional Backtrack.
   void BranchOrBacktrack(Condition condition, Label* to);
 
-  // Generate code to perform case-canonicalization on the register.
-  void Canonicalize(Register register);
-
   // Read a character from input at the given offset from the current
   // position.
-  void ReadChar(Register destination, int offset);
+  void LoadCurrentCharToRegister(int cp_offset);
 
   // Load the address of a "constant buffer" (a slice of a byte array)
   // into a register. The address is computed from the ByteArray* address
   // and an offset. Uses no extra registers.
   void LoadConstantBufferAddress(Register reg, ArraySlice* buffer);
 
-  // Read the current character into the destination register.
-  void ReadCurrentChar(Register destination);
-
   // Adds code that checks whether preemption has been requested
   // (and checks if we have hit the stack limit too).
   void CheckStackLimit();
index 046d6817a6befa8e07ac56a26202a8d244d9c0b5..80dff254d3b7e0a27a1d4932aca265cd741a9ffb 100644 (file)
@@ -183,6 +183,7 @@ void RegExpMacroAssemblerTracer::CheckCharacter(uc16 c, Label* on_equal) {
 
 void RegExpMacroAssemblerTracer::CheckNotAtStart(Label* on_not_at_start) {
   PrintF(" CheckNotAtStart(label[%08x]);\n", on_not_at_start);
+  assembler_->CheckNotAtStart(on_not_at_start);
 }
 
 
index 4f075a1fb2e568d8a31ee54bf07f09f10257e9e3..210e5bb0f96dcba2d382f4a63c8c21ca7db5829a 100644 (file)
@@ -582,9 +582,6 @@ TEST(MacroAssembler) {
 #ifndef ARM  // IA32 only tests.
 
 TEST(MacroAssemblerIA32Success) {
-  typedef bool (*AsciiTest) (
-      SeqAsciiString** base, int start_index, int end_index, int* captures);
-
   V8::Initialize(NULL);
 
   // regexp-macro-assembler-ia32 needs a handle scope to allocate
@@ -597,7 +594,6 @@ TEST(MacroAssemblerIA32Success) {
 
   Handle<Object> code_object = m.GetCode();
   Handle<Code> code = Handle<Code>::cast(code_object);
-  AsciiTest test = FUNCTION_CAST<AsciiTest>(code->entry());
 
   int captures[4] = {42, 37, 87, 117};
   Handle<String> input = Factory::NewStringFromAscii(CStrVector("foofoo"));
@@ -606,8 +602,12 @@ TEST(MacroAssemblerIA32Success) {
   int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
   int end_offset = start_offset + seq_input->length();
 
-  bool success =
-      test(seq_input.location(), start_offset, end_offset, captures);
+  bool success = RegExpMacroAssemblerIA32::Execute(*code,
+                                                   seq_input.location(),
+                                                   start_offset,
+                                                   end_offset,
+                                                   captures,
+                                                   true);
 
   CHECK(success);
   CHECK_EQ(-1, captures[0]);
@@ -618,9 +618,6 @@ TEST(MacroAssemblerIA32Success) {
 
 
 TEST(MacroAssemblerIA32Simple) {
-  typedef bool (*AsciiTest) (
-      SeqAsciiString** base, int start_index, int end_index, int* captures);
-
   V8::Initialize(NULL);
 
   // regexp-macro-assembler-ia32 needs a handle scope to allocate
@@ -643,7 +640,6 @@ TEST(MacroAssemblerIA32Simple) {
 
   Handle<Object> code_object = m.GetCode();
   Handle<Code> code = Handle<Code>::cast(code_object);
-  AsciiTest test = FUNCTION_CAST<AsciiTest>(code->entry());
 
   int captures[4] = {42, 37, 87, 117};
   Handle<String> input = Factory::NewStringFromAscii(CStrVector("foofoo"));
@@ -652,8 +648,12 @@ TEST(MacroAssemblerIA32Simple) {
   int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
   int end_offset = start_offset + seq_input->length();
 
-  bool success =
-      test(seq_input.location(), start_offset, end_offset, captures);
+  bool success = RegExpMacroAssemblerIA32::Execute(*code,
+                                                   seq_input.location(),
+                                                   start_offset,
+                                                   end_offset,
+                                                   captures,
+                                                   true);
 
   CHECK(success);
   CHECK_EQ(0, captures[0]);
@@ -667,16 +667,18 @@ TEST(MacroAssemblerIA32Simple) {
   start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
   end_offset = start_offset + seq_input->length();
 
-  success = test(seq_input.location(), start_offset, end_offset, captures);
+  success = RegExpMacroAssemblerIA32::Execute(*code,
+                                              seq_input.location(),
+                                              start_offset,
+                                              end_offset,
+                                              captures,
+                                              true);
 
   CHECK(!success);
 }
 
 
 TEST(MacroAssemblerIA32SimpleUC16) {
-  typedef bool (*UC16Test) (
-      SeqTwoByteString** base, int start_index, int end_index, int* captures);
-
   V8::Initialize(NULL);
 
   // regexp-macro-assembler-ia32 needs a handle scope to allocate
@@ -699,7 +701,6 @@ TEST(MacroAssemblerIA32SimpleUC16) {
 
   Handle<Object> code_object = m.GetCode();
   Handle<Code> code = Handle<Code>::cast(code_object);
-  UC16Test test = FUNCTION_CAST<UC16Test>(code->entry());
 
   int captures[4] = {42, 37, 87, 117};
   const uc16 input_data[6] = {'f', 'o', 'o', 'f', 'o', '\xa0'};
@@ -710,8 +711,12 @@ TEST(MacroAssemblerIA32SimpleUC16) {
   int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
   int end_offset = start_offset + seq_input->length() * sizeof(uc16);
 
-  bool success =
-      test(seq_input.location(), start_offset, end_offset, captures);
+  bool success = RegExpMacroAssemblerIA32::Execute(*code,
+                                                   seq_input.location(),
+                                                   start_offset,
+                                                   end_offset,
+                                                   captures,
+                                                   true);
 
   CHECK(success);
   CHECK_EQ(0, captures[0]);
@@ -726,16 +731,18 @@ TEST(MacroAssemblerIA32SimpleUC16) {
   start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
   end_offset = start_offset + seq_input->length() * sizeof(uc16);
 
-  success = test(seq_input.location(), start_offset, end_offset, captures);
+  success = RegExpMacroAssemblerIA32::Execute(*code,
+                                              seq_input.location(),
+                                              start_offset,
+                                              end_offset,
+                                              captures,
+                                              true);
 
   CHECK(!success);
 }
 
 
 TEST(MacroAssemblerIA32Backtrack) {
-  typedef bool (*AsciiTest) (
-      SeqAsciiString** base, int start_index, int end_index, int* captures);
-
   V8::Initialize(NULL);
 
   // regexp-macro-assembler-ia32 needs a handle scope to allocate
@@ -760,7 +767,6 @@ TEST(MacroAssemblerIA32Backtrack) {
 
   Handle<Object> code_object = m.GetCode();
   Handle<Code> code = Handle<Code>::cast(code_object);
-  AsciiTest test = FUNCTION_CAST<AsciiTest>(code->entry());
 
   Handle<String> input = Factory::NewStringFromAscii(CStrVector("foofoo"));
   Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
@@ -768,17 +774,81 @@ TEST(MacroAssemblerIA32Backtrack) {
   int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
   int end_offset = start_offset + seq_input->length();
 
-  bool success =
-      test(seq_input.location(), start_offset, end_offset, NULL);
+  bool success = RegExpMacroAssemblerIA32::Execute(*code,
+                                                   seq_input.location(),
+                                                   start_offset,
+                                                   end_offset,
+                                                   NULL,
+                                                   true);
 
   CHECK(!success);
 }
 
+TEST(MacroAssemblerIA32AtStart) {
+  V8::Initialize(NULL);
+
+  // regexp-macro-assembler-ia32 needs a handle scope to allocate
+  // byte-arrays for constants.
+  v8::HandleScope scope;
 
-TEST(MacroAssemblerIA32Registers) {
-  typedef bool (*AsciiTest) (
-      SeqAsciiString** base, int start_index, int end_index, int* captures);
+  RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 0);
+
+  uc16 foo_chars[3] = {'f', 'o', 'o'};
+  Vector<const uc16> foo(foo_chars, 3);
+
+  Label not_at_start, newline, fail;
+  m.CheckNotAtStart(&not_at_start);
+  // Check that prevchar = '\n' and current = 'f'.
+  m.CheckCharacter('\n', &newline);
+  m.Bind(&fail);
+  m.Fail();
+  m.Bind(&newline);
+  m.LoadCurrentCharacter(0, &fail);
+  m.CheckNotCharacter('f', &fail);
+  m.Succeed();
 
+  m.Bind(&not_at_start);
+  // Check that prevchar = 'o' and current = 'b'.
+  Label prevo;
+  m.CheckCharacter('o', &prevo);
+  m.Fail();
+  m.Bind(&prevo);
+  m.LoadCurrentCharacter(0, &fail);
+  m.CheckNotCharacter('b', &fail);
+  m.Succeed();
+
+  Handle<Object> code_object = m.GetCode();
+  Handle<Code> code = Handle<Code>::cast(code_object);
+
+  Handle<String> input = Factory::NewStringFromAscii(CStrVector("foobar"));
+  Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
+  Address start_adr = seq_input->GetCharsAddress();
+  int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
+  int end_offset = start_offset + seq_input->length();
+
+  bool success = RegExpMacroAssemblerIA32::Execute(*code,
+                                                   seq_input.location(),
+                                                   start_offset,
+                                                   end_offset,
+                                                   NULL,
+                                                   true);
+
+  CHECK(success);
+
+  start_offset += 3;
+  success = RegExpMacroAssemblerIA32::Execute(*code,
+                                              seq_input.location(),
+                                              start_offset,
+                                              end_offset,
+                                              NULL,
+                                              false);
+
+  CHECK(success);
+}
+
+
+
+TEST(MacroAssemblerIA32Registers) {
   V8::Initialize(NULL);
 
   // regexp-macro-assembler-ia32 needs a handle scope to allocate
@@ -850,7 +920,6 @@ TEST(MacroAssemblerIA32Registers) {
 
   Handle<Object> code_object = m.GetCode();
   Handle<Code> code = Handle<Code>::cast(code_object);
-  AsciiTest test = FUNCTION_CAST<AsciiTest>(code->entry());
 
   // String long enough for test (content doesn't matter).
   Handle<String> input =
@@ -861,8 +930,12 @@ TEST(MacroAssemblerIA32Registers) {
   int end_offset = start_offset + seq_input->length();
 
   int output[5];
-  bool success =
-      test(seq_input.location(), start_offset, end_offset, output);
+  bool success = RegExpMacroAssemblerIA32::Execute(*code,
+                                                   seq_input.location(),
+                                                   start_offset,
+                                                   end_offset,
+                                                   output,
+                                                   true);
 
   CHECK(success);
   CHECK_EQ(0, output[0]);