Separately growing stack for irregexp ia32 backtrack stack.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 12 Jan 2009 13:05:23 +0000 (13:05 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 12 Jan 2009 13:05:23 +0000 (13:05 +0000)
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1053 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

18 files changed:
src/SConscript
src/assembler.cc
src/assembler.h
src/jsregexp.cc
src/regexp-macro-assembler-ia32.cc
src/regexp-macro-assembler-ia32.h
src/regexp-macro-assembler-irregexp.cc
src/regexp-macro-assembler-irregexp.h
src/regexp-macro-assembler-tracer.cc
src/regexp-macro-assembler-tracer.h
src/regexp-macro-assembler.cc
src/regexp-macro-assembler.h
src/regexp-stack.cc [new file with mode: 0644]
src/regexp-stack.h [new file with mode: 0644]
src/v8threads.cc
test/cctest/test-regexp.cc
tools/visual_studio/v8_base.vcproj
tools/visual_studio/v8_base_arm.vcproj

index c1bd12b..092fe8d 100644 (file)
@@ -44,11 +44,11 @@ SOURCES = {
     'interpreter-irregexp.cc', 'jsregexp.cc', 'log.cc', 'mark-compact.cc',
     'messages.cc', 'objects.cc', 'parser.cc', 'property.cc',
     'regexp-macro-assembler.cc', 'regexp-macro-assembler-irregexp.cc',
-    'rewriter.cc', 'runtime.cc', 'scanner.cc', 'scopeinfo.cc', 'scopes.cc',
-    'serialize.cc', 'snapshot-common.cc', 'spaces.cc', 'string-stream.cc',
-    'stub-cache.cc', 'token.cc', 'top.cc', 'unicode.cc', 'usage-analyzer.cc',
-    'utils.cc', 'v8-counters.cc', 'v8.cc', 'v8threads.cc', 'variables.cc',
-    'zone.cc'
+    'regexp-stack.cc', 'rewriter.cc', 'runtime.cc', 'scanner.cc',
+    'scopeinfo.cc', 'scopes.cc', 'serialize.cc', 'snapshot-common.cc',
+    'spaces.cc', 'string-stream.cc', 'stub-cache.cc', 'token.cc', 'top.cc',
+    'unicode.cc', 'usage-analyzer.cc', 'utils.cc', 'v8-counters.cc', 'v8.cc',
+    'v8threads.cc', 'variables.cc', 'zone.cc'
   ],
   'arch:arm':  ['assembler-arm.cc', 'builtins-arm.cc', 'codegen-arm.cc',
       'cpu-arm.cc', 'debug-arm.cc', 'disasm-arm.cc', 'frames-arm.cc',
index c56eb2f..ad4b24c 100644 (file)
@@ -41,6 +41,7 @@
 #include "runtime.h"
 #include "serialize.h"
 #include "stub-cache.h"
+#include "regexp-stack.h"
 
 namespace v8 { namespace internal {
 
@@ -551,6 +552,11 @@ ExternalReference ExternalReference::address_of_stack_guard_limit() {
 }
 
 
+ExternalReference ExternalReference::address_of_regexp_stack_limit() {
+  return ExternalReference(RegExpStack::limit_address());
+}
+
+
 ExternalReference ExternalReference::debug_break() {
   return ExternalReference(FUNCTION_ADDR(Debug::Break));
 }
index 7bd117c..097bc84 100644 (file)
@@ -442,6 +442,9 @@ class ExternalReference BASE_EMBEDDED {
   // Static variable StackGuard::address_of_limit()
   static ExternalReference address_of_stack_guard_limit();
 
+  // Static variable RegExpStack::limit_address()
+  static ExternalReference address_of_regexp_stack_limit();
+
   // Function Debug::Break()
   static ExternalReference debug_break();
 
index e072d0d..37ba35f 100644 (file)
@@ -40,6 +40,7 @@
 #include "regexp-macro-assembler.h"
 #include "regexp-macro-assembler-tracer.h"
 #include "regexp-macro-assembler-irregexp.h"
+#include "regexp-stack.h"
 
 #ifdef ARM
 #include "regexp-macro-assembler-arm.h"
@@ -913,7 +914,7 @@ Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<FixedArray> irregexp,
         }
         res = RegExpMacroAssemblerIA32::Execute(
             *code,
-            &address,
+            const_cast<Address*>(&address),
             start_offset << char_size_shift,
             end_offset << char_size_shift,
             offsets_vector,
@@ -925,7 +926,7 @@ Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<FixedArray> irregexp,
         int byte_offset = char_address - reinterpret_cast<Address>(*subject);
         res = RegExpMacroAssemblerIA32::Execute(
             *code,
-            subject.location(),
+            reinterpret_cast<Address*>(subject.location()),
             byte_offset + (start_offset << char_size_shift),
             byte_offset + (end_offset << char_size_shift),
             offsets_vector,
@@ -1347,8 +1348,18 @@ int GenerationVariant::FindAffectedRegisters(OutSet* affected_registers) {
 void GenerationVariant::PushAffectedRegisters(RegExpMacroAssembler* assembler,
                                               int max_register,
                                               OutSet& affected_registers) {
-  for (int reg = 0; reg <= max_register; reg++) {
-    if (affected_registers.Get(reg)) assembler->PushRegister(reg);
+  // Stay safe and check every half times the limit.
+  // (Round up in case the limit is 1).
+  int push_limit = (assembler->stack_limit_slack() + 1) / 2;
+  for (int reg = 0, pushes = 0; reg <= max_register; reg++) {
+    if (affected_registers.Get(reg)) {
+      pushes++;
+      RegExpMacroAssembler::StackCheckFlag check_stack_limit =
+          (pushes % push_limit) == 0 ?
+                RegExpMacroAssembler::kCheckStackLimit :
+                RegExpMacroAssembler::kNoStackLimitCheck;
+      assembler->PushRegister(reg, check_stack_limit);
+    }
   }
 }
 
index d743268..56846af 100644 (file)
@@ -30,6 +30,7 @@
 #include "unicode.h"
 #include "log.h"
 #include "ast.h"
+#include "regexp-stack.h"
 #include "macro-assembler.h"
 #include "regexp-macro-assembler.h"
 #include "macro-assembler-ia32.h"
@@ -46,12 +47,15 @@ namespace v8 { namespace internal {
  * - esi : end of input (points to byte after last character in input).
  * - ebp : points to the location above the registers on the stack,
  *         as if by the "enter <register_count>" opcode.
- * - esp : points to tip of backtracking stack.
+ * - esp : points to tip of C stack.
+ * - ecx : points to tip of backtrack stack
  *
  * The registers eax, ebx and ecx are free to use for computations.
  *
  * Each call to a public method should retain this convention.
  * The stack will have the following structure:
+ *       - stack_area_top     (High end of the memory area to use as
+ *                             backtracking stack)
  *       - 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)
@@ -59,9 +63,9 @@ namespace v8 { namespace internal {
  *                            to *string_base)
  *       - void** string_base (location of a handle containing the string)
  *       - return address
- *       - backup of esi
- *       - backup of edi
- *       - backup of ebx
+ *       - backup of caller esi
+ *       - backup of caller edi
+ *       - backup of caller ebx
  * ebp-> - old ebp
  *       - register 0  ebp[-4]  (Only positions must be stored in the first
  *       - register 1  ebp[-8]   num_saved_registers_ registers)
@@ -77,7 +81,8 @@ namespace v8 { namespace internal {
  *               int start_offset,
  *               int end_offset,
  *               int* capture_output_array,
- *               bool at_start)
+ *               bool at_start,
+ *               byte* stack_area_top)
  */
 
 #define __ masm_->
@@ -110,6 +115,12 @@ RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() {
   backtrack_label_.Unuse();
   exit_label_.Unuse();
   check_preempt_label_.Unuse();
+  stack_overflow_label_.Unuse();
+}
+
+
+int RegExpMacroAssemblerIA32::stack_limit_slack()  {
+  return RegExpStack::kStackLimitSlack;
 }
 
 
@@ -124,12 +135,18 @@ void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) {
 void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) {
   ASSERT(reg >= 0);
   ASSERT(reg < num_registers_);
-  __ add(register_location(reg), Immediate(by));
+  if (by != 0) {
+    __ add(register_location(reg), Immediate(by));
+  }
 }
 
 
 void RegExpMacroAssemblerIA32::Backtrack() {
-  SafeReturn();
+  CheckPreemption();
+  // Pop Code* offset from backtrack stack, add Code* and jump to location.
+  Pop(ebx);
+  __ add(Operand(ebx), Immediate(self_));
+  __ jmp(Operand(ebx));
 }
 
 
@@ -137,22 +154,11 @@ void RegExpMacroAssemblerIA32::Bind(Label* label) {
   __ bind(label);
 }
 
+
 void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start,
                                            Label* bitmap,
                                            Label* on_zero) {
   UNIMPLEMENTED();
-  __ mov(eax, current_character());
-  __ sub(Operand(eax), Immediate(start));
-  __ cmp(eax, 64);  // FIXME: 64 = length_of_bitmap_in_bits.
-  BranchOrBacktrack(greater_equal, on_zero);
-  __ mov(ebx, eax);
-  __ shr(ebx, 3);
-  // TODO(lrn): Where is the bitmap stored? Pass the bitmap as argument instead.
-  // __ mov(ecx, position_of_bitmap);
-  __ movzx_b(ebx, Operand(ecx, ebx, times_1, 0));
-  __ and_(eax, (1<<3)-1);
-  __ bt(Operand(ebx), eax);
-  BranchOrBacktrack(carry, on_zero);
 }
 
 
@@ -169,8 +175,10 @@ void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
 
 
 void RegExpMacroAssemblerIA32::CheckNotAtStart(Label* on_not_at_start) {
+  // Did we start the match at the start of the string at all?
   __ cmp(Operand(ebp, kAtStart), Immediate(0));
   BranchOrBacktrack(equal, on_not_at_start);
+  // If we did, are we still at the start of the input?
   __ mov(eax, Operand(ebp, kInputEndOffset));
   __ add(eax, Operand(edi));
   __ cmp(eax, Operand(ebp, kInputStartOffset));
@@ -191,6 +199,7 @@ void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
   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(Operand(edi), Immediate(-(byte_offset + byte_length)));
     BranchOrBacktrack(greater, on_failure);
   }
@@ -222,9 +231,9 @@ void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
 
 void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) {
   Label fallthrough;
-  __ cmp(edi, Operand(esp, 0));
+  __ cmp(edi, Operand(backtrack_stackpointer(), 0));
   __ j(not_equal, &fallthrough);
-  __ add(Operand(esp), Immediate(4));  // Pop.
+  __ add(Operand(backtrack_stackpointer()), Immediate(kPointerSize));  // Pop.
   BranchOrBacktrack(no_condition, on_equal);
   __ bind(&fallthrough);
 }
@@ -234,20 +243,31 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
     int start_reg,
     Label* on_no_match) {
   Label fallthrough;
-  __ mov(edx, register_location(start_reg));
-  __ mov(ecx, register_location(start_reg + 1));
-  __ sub(ecx, Operand(edx));  // Length to check.
-  BranchOrBacktrack(less, on_no_match);
+  __ mov(edx, register_location(start_reg));  // Index of start of capture
+  __ mov(ebx, register_location(start_reg + 1));  // Index of end of capture
+  __ sub(ebx, Operand(edx));  // Length of capture.
+
+  // The length of a capture should not be negative. This can only happen
+  // if the end of the capture is unrecorded, or at a point earlier than
+  // the start of the capture.
+  BranchOrBacktrack(less, on_no_match, not_taken);
+
+  // If length is zero, either the capture is empty or it is completely
+  // uncaptured. In either case succeed immediately.
   __ j(equal, &fallthrough);
 
   if (mode_ == ASCII) {
     Label success;
     Label fail;
     Label loop_increment;
+    // Save register contents to make the registers available below.
     __ push(edi);
-    __ add(edx, Operand(esi));
-    __ add(edi, Operand(esi));
-    __ add(ecx, Operand(edi));
+    __ push(backtrack_stackpointer());
+    // After this, the eax, ebx, ecx, edx and edi registers are available.
+
+    __ add(edx, Operand(esi));  // Start of capture
+    __ add(edi, Operand(esi));  // Start of text to match against capture.
+    __ add(ebx, Operand(edi));  // End of text to match against capture.
 
     Label loop;
     __ bind(&loop);
@@ -255,55 +275,71 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
     __ cmpb_al(Operand(edx, 0));
     __ j(equal, &loop_increment);
 
-    // Compare lower-case if letters.
-    __ or_(eax, 0x20);  // To lower-case.
-    __ lea(ebx, Operand(eax, -'a'));
-    __ cmp(ebx, static_cast<int32_t>('z' - 'a'));
+    // Mismatch, try case-insensitive match (converting letters to lower-case).
+    __ or_(eax, 0x20);  // Convert match character to lower-case.
+    __ lea(ecx, Operand(eax, -'a'));
+    __ cmp(ecx, static_cast<int32_t>('z' - 'a'));  // Is eax a lowercase letter?
     __ j(above, &fail);
-    __ movzx_b(ebx, Operand(edx, 0));
-    __ or_(ebx, 0x20);  // To-lower-case
-    __ cmp(eax, Operand(ebx));
+    // Also convert capture character.
+    __ movzx_b(ecx, Operand(edx, 0));
+    __ or_(ecx, 0x20);
+
+    __ cmp(eax, Operand(ecx));
     __ j(not_equal, &fail);
 
     __ bind(&loop_increment);
+    // Increment pointers into match and capture strings.
     __ add(Operand(edx), Immediate(1));
     __ add(Operand(edi), Immediate(1));
-    __ cmp(edi, Operand(ecx));
+    // Compare to end of match, and loop if not done.
+    __ cmp(edi, Operand(ebx));
     __ j(below, &loop, taken);
     __ jmp(&success);
 
     __ bind(&fail);
+    // Restore original values before failing.
+    __ pop(backtrack_stackpointer());
     __ pop(edi);
     BranchOrBacktrack(no_condition, on_no_match);
 
     __ bind(&success);
-    __ pop(eax);  // discard original value of edi
+    // Restore original value before continuing.
+    __ pop(backtrack_stackpointer());
+    // Drop original value of character position.
+    __ add(Operand(esp), Immediate(kPointerSize));
+    // Compute new value of character position after the matched part.
     __ sub(edi, Operand(esi));
   } else {
     ASSERT(mode_ == UC16);
+    // Save registers before calling C function.
     __ push(esi);
     __ push(edi);
-    __ push(ecx);
+    __ push(backtrack_stackpointer());
+    __ push(ebx);
     const int four_arguments = 4;
     FrameAlign(four_arguments);
-    // Put arguments on stack.
-    __ mov(Operand(esp, 3 * kPointerSize), ecx);
-    __ mov(ebx, Operand(ebp, kInputEndOffset));
-    __ add(edi, Operand(ebx));
+    // Put arguments into allocated stack area.
+    __ mov(Operand(esp, 3 * kPointerSize), ebx);
+    __ mov(ecx, Operand(ebp, kInputEndOffset));
+    __ add(edi, Operand(ecx));
     __ mov(Operand(esp, 2 * kPointerSize), edi);
-    __ add(eax, Operand(ebx));
+    __ add(eax, Operand(ecx));
     __ mov(Operand(esp, 1 * kPointerSize), eax);
     __ mov(eax, Operand(ebp, kInputBuffer));
     __ mov(Operand(esp, 0 * kPointerSize), eax);
     Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16);
     CallCFunction(function_address, four_arguments);
-    __ pop(ecx);
+    // Pop original values before reacting on result value.
+    __ pop(ebx);
+    __ pop(backtrack_stackpointer());
     __ pop(edi);
     __ pop(esi);
 
+    // Check if function returned non-zero for success or zero for failure.
     __ or_(eax, Operand(eax));
     BranchOrBacktrack(zero, on_no_match);
-    __ add(edi, Operand(ecx));
+    // On success, increment position by length of capture.
+    __ add(edi, Operand(ebx));
   }
   __ bind(&fallthrough);
 }
@@ -315,45 +351,60 @@ void RegExpMacroAssemblerIA32::CheckNotBackReference(
   Label fallthrough;
   Label success;
   Label fail;
+
+  // Find length of back-referenced capture.
   __ mov(edx, register_location(start_reg));
-  __ mov(ecx, register_location(start_reg + 1));
-  __ sub(ecx, Operand(edx));  // Length to check.
+  __ mov(eax, register_location(start_reg + 1));
+  __ sub(eax, Operand(edx));  // Length to check.
+  // Fail on partial or illegal capture (start of capture after end of capture).
   BranchOrBacktrack(less, on_no_match);
+  // Succeed on empty capture (including no capture)
   __ j(equal, &fallthrough);
-  // Check that there are sufficient characters left in the input.
 
+  // Check that there are sufficient characters left in the input.
   __ mov(ebx, edi);
-  __ add(ebx, Operand(ecx));
+  __ add(ebx, Operand(eax));
   BranchOrBacktrack(greater, on_no_match);
 
-  __ mov(ebx, edi);
-  __ add(edi, Operand(esi));
-  __ add(edx, Operand(esi));
-  __ add(ecx, Operand(edi));
+  // Save register to make it available below.
+  __ push(backtrack_stackpointer());
+
+  // Compute pointers to match string and capture string
+  __ lea(ebx, Operand(esi, edi, times_1, 0));  // Start of match.
+  __ add(edx, Operand(esi));  // Start of capture.
+  __ lea(ecx, Operand(eax, ebx, times_1, 0));  // End of match
 
   Label loop;
   __ bind(&loop);
   if (mode_ == ASCII) {
     __ movzx_b(eax, Operand(edx, 0));
-    __ cmpb_al(Operand(edi, 0));
+    __ cmpb_al(Operand(ebx, 0));
   } else {
     ASSERT(mode_ == UC16);
     __ movzx_w(eax, Operand(edx, 0));
-    __ cmpw_ax(Operand(edi, 0));
+    __ cmpw_ax(Operand(ebx, 0));
   }
   __ j(not_equal, &fail);
+  // Increment pointers into capture and match string.
   __ add(Operand(edx), Immediate(char_size()));
-  __ add(Operand(edi), Immediate(char_size()));
-  __ cmp(edi, Operand(ecx));
+  __ add(Operand(ebx), Immediate(char_size()));
+  // Check if we have reached end of match area.
+  __ cmp(ebx, Operand(ecx));
   __ j(below, &loop);
   __ jmp(&success);
 
   __ bind(&fail);
-  __ mov(edi, ebx);
+  // Restore backtrack stackpointer.
+  __ pop(backtrack_stackpointer());
   BranchOrBacktrack(no_condition, on_no_match);
 
   __ bind(&success);
-  __ sub(edi, Operand(esi));
+  // Move current character position to position after match.
+  __ mov(edi, ecx);
+  __ sub(Operand(edi), esi);
+  // Restore backtrack stackpointer.
+  __ pop(backtrack_stackpointer());
+
   __ bind(&fallthrough);
 }
 
@@ -406,6 +457,7 @@ void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusAnd(
   BranchOrBacktrack(not_equal, on_not_equal);
 }
 
+
 bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
                                                           int cp_offset,
                                                           bool check_offset,
@@ -428,7 +480,7 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
       // Check range 0x09..0x0d
       __ sub(Operand(current_character()), Immediate('\t'));
       __ cmp(current_character(), '\r' - '\t');
-      BranchOrBacktrack(above_equal, on_no_match);
+      BranchOrBacktrack(above, on_no_match);
       __ bind(&success);
       return true;
     }
@@ -446,7 +498,7 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
       BranchOrBacktrack(equal, on_no_match);
       __ sub(Operand(current_character()), Immediate('\t'));
       __ cmp(current_character(), '\r' - '\t');
-      BranchOrBacktrack(below, on_no_match);
+      BranchOrBacktrack(below_equal, on_no_match);
       return true;
     }
     return false;
@@ -459,7 +511,7 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
     }
     __ sub(Operand(current_character()), Immediate('0'));
     __ cmp(current_character(), '9' - '0');
-    BranchOrBacktrack(greater_equal, on_no_match);
+    BranchOrBacktrack(above, on_no_match);
     return true;
   case 'D':
     // Match non ASCII-digits
@@ -470,7 +522,7 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
     }
     __ sub(Operand(current_character()), Immediate('0'));
     __ cmp(current_character(), '9' - '0');
-    BranchOrBacktrack(below, on_no_match);
+    BranchOrBacktrack(below_equal, on_no_match);
     return true;
   case '.': {
     // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
@@ -479,18 +531,18 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
     } else {
       LoadCurrentCharacterUnchecked(cp_offset, 1);
     }
-    // Compute hash value so exactly 0x0a and 0x0d become zero.
-    __ sub(Operand(current_character()), Immediate('\n'));
-    __ mov(eax, current_character());
-    __ and_(current_character(), 0x01);
-    __ shr(eax, 1);
-    __ xor_(current_character(), Operand(eax));
-    BranchOrBacktrack(equal, on_no_match);
+    __ xor_(Operand(current_character()), Immediate(0x01));
+    // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
+    __ sub(Operand(current_character()), Immediate(0x0b));
+    __ cmp(current_character(), 0x0c - 0x0b);
+    BranchOrBacktrack(below_equal, on_no_match);
     if (mode_ == UC16) {
       // Compare original value to 0x2028 and 0x2029, using the already
-      // computed ((current_char - '\n') >> 1) in eax.
-      __ cmp(eax, (0x2028 - '\n') >> 1);
-      BranchOrBacktrack(equal, on_no_match);
+      // computed (current_char ^ 0x01 - 0x0b). I.e., check for
+      // 0x201d (0x2028 - 0x0b) or 0x201e.
+      __ sub(Operand(current_character()), Immediate(0x2028 - 0x0b));
+      __ cmp(current_character(), 1);
+      BranchOrBacktrack(below_equal, on_no_match);
     }
     return true;
   }
@@ -511,35 +563,6 @@ void RegExpMacroAssemblerIA32::DispatchHalfNibbleMap(
     Label* half_nibble_map,
     const Vector<Label*>& destinations) {
   UNIMPLEMENTED();
-  __ mov(eax, current_character());
-  __ sub(Operand(eax), Immediate(start));
-
-  __ mov(ecx, eax);
-  __ shr(eax, 2);
-  // FIXME: ecx must hold address of map
-  __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
-  __ and_(ecx, 0x03);
-  __ add(ecx, Operand(ecx));
-  __ shr(eax);  // Shift right cl times
-
-  Label second_bit_set, case_3, case_1;
-  __ test(eax, Immediate(0x02));
-  __ j(not_zero, &second_bit_set);
-  __ test(eax, Immediate(0x01));
-  __ j(not_zero, &case_1);
-  // Case 0:
-  __ jmp(destinations[0]);
-  __ bind(&case_1);
-  // Case 1:
-  __ jmp(destinations[1]);
-  __ bind(&second_bit_set);
-  __ test(eax, Immediate(0x01));
-  __ j(not_zero, &case_3);
-  // Case 2
-  __ jmp(destinations[2]);
-  __ bind(&case_3);
-  // Case 3:
-  __ jmp(destinations[3]);
 }
 
 
@@ -548,17 +571,6 @@ void RegExpMacroAssemblerIA32::DispatchByteMap(
     Label* byte_map,
     const Vector<Label*>& destinations) {
   UNIMPLEMENTED();
-
-  Label fallthrough;
-  __ mov(eax, current_character());
-  __ sub(Operand(eax), Immediate(start));
-  __ cmp(eax, 64);  // FIXME: 64 = size of map. Found somehow??
-  __ j(greater_equal, &fallthrough);
-  // TODO(lrn): ecx must hold address of map
-  __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
-  // jump table: jump to destinations[eax];
-
-  __ bind(&fallthrough);
 }
 
 
@@ -567,16 +579,6 @@ void RegExpMacroAssemblerIA32::DispatchHighByteMap(
     Label* byte_map,
     const Vector<Label*>& destinations) {
   UNIMPLEMENTED();
-
-  Label fallthrough;
-  __ mov(eax, current_character());
-  __ shr(eax, 8);
-  __ sub(Operand(eax), Immediate(start));
-  __ cmp(eax, destinations.length() - start);
-  __ j(greater_equal, &fallthrough);
-
-  // TODO(lrn) jumptable: jump to destinations[eax]
-  __ bind(&fallthrough);
 }
 
 
@@ -586,6 +588,7 @@ void RegExpMacroAssemblerIA32::EmitOrLink(Label* label) {
 
 
 void RegExpMacroAssemblerIA32::Fail() {
+  ASSERT(FAILURE == 0);  // Return value for failure is zero.
   __ xor_(eax, Operand(eax));  // zero eax.
   __ jmp(&exit_label_);
 }
@@ -602,6 +605,46 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
   __ push(esi);
   __ push(edi);
   __ push(ebx);  // Callee-save on MacOS.
+
+  // Check if we have space on the stack for registers.
+  Label retry_stack_check;
+  Label stack_limit_hit;
+  Label stack_ok;
+
+  __ bind(&retry_stack_check);
+  ExternalReference stack_guard_limit =
+      ExternalReference::address_of_stack_guard_limit();
+  __ mov(ecx, esp);
+  __ sub(ecx, Operand::StaticVariable(stack_guard_limit));
+  // Handle it if the stack pointer is already below the stack limit.
+  __ j(below_equal, &stack_limit_hit, not_taken);
+  // Check if there is room for num_registers + ebp above the stack limit.
+  __ cmp(ecx, (num_registers_ + 1) * kPointerSize);
+  __ j(above_equal, &stack_ok, taken);
+  // Exit with exception.
+  __ mov(eax, EXCEPTION);
+  Label exit_without_leave;
+  __ jmp(&exit_without_leave);
+
+  __ bind(&stack_limit_hit);
+  int num_arguments = 2;
+  FrameAlign(num_arguments);
+  __ mov(Operand(esp, 1 * kPointerSize), Immediate(self_));
+  __ lea(eax, Operand(esp, -kPointerSize));
+  __ mov(Operand(esp, 0 * kPointerSize), eax);
+  CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments);
+  __ or_(eax, Operand(eax));
+  // If returned value is non-zero, the stack guard reports the actual
+  // stack limit being hit and an exception has already been raised.
+  // Otherwise it was a preemption and we just check the limit again.
+  __ j(equal, &retry_stack_check);
+  // Return value was non-zero. Exit with exception.
+  __ mov(eax, EXCEPTION);
+  __ jmp(&exit_without_leave);
+
+  __ bind(&stack_ok);
+
+  // Allocate space on stack for registers.
   __ enter(Immediate(num_registers_ * kPointerSize));
   // Load string length.
   __ mov(esi, Operand(ebp, kInputEndOffset));
@@ -617,15 +660,32 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
   __ add(esi, Operand(edx));
   if (num_saved_registers_ > 0) {
     // Fill saved registers with initial value = start offset - 1
-    __ mov(ecx, -num_saved_registers_);
-    __ mov(eax, Operand(edi));
-    __ sub(Operand(eax), Immediate(char_size()));
+    // Fill in stack push order, to avoid accessing across an unwritten
+    // page (a problem on Windows).
+    const int kRegisterZeroEBPOffset = -1;
+    __ mov(ecx, kRegisterZeroEBPOffset);
+    // Set eax to address of char before start of input.
+    __ lea(eax, Operand(edi, -char_size()));
     Label init_loop;
     __ bind(&init_loop);
     __ mov(Operand(ebp, ecx, times_4, +0), eax);
-    __ inc(ecx);
-    __ j(not_equal, &init_loop);
+    __ sub(Operand(ecx), Immediate(1));
+    __ cmp(ecx, -num_saved_registers_);
+    __ j(greater_equal, &init_loop);
+  }
+  // Ensure that we have written to each stack page. Skipping a page on
+  // Windows can cause segmentation faults. Assuming page size is 4k.
+  const int kPageSize = 4096;
+  const int kRegistersPerPage = kPageSize / kPointerSize;
+  for (int i = num_saved_registers_ + kRegistersPerPage - 1;
+      i < num_registers_;
+      i += kRegistersPerPage) {
+    __ mov(register_location(i), eax);  // One write every page.
   }
+
+
+  // Initialize backtrack stack pointer.
+  __ mov(backtrack_stackpointer(), Operand(ebp, kStackHighEnd));
   // Load previous char as initial value of current-character.
   Label at_start;
   __ cmp(Operand(ebp, kAtStart), Immediate(0));
@@ -655,11 +715,12 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
         __ mov(Operand(ebx, i * kPointerSize), eax);
       }
     }
-    __ mov(eax, Immediate(1));
+    __ mov(eax, Immediate(SUCCESS));
   }
   // Exit and return eax
   __ bind(&exit_label_);
   __ leave();
+  __ bind(&exit_without_leave);  // For exiting before doing enter.
   __ pop(ebx);
   __ pop(edi);
   __ pop(esi);
@@ -671,16 +732,16 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
     Backtrack();
   }
 
+  Label exit_with_exception;
+
   // Preempt-code
   if (check_preempt_label_.is_linked()) {
     __ bind(&check_preempt_label_);
-    // TODO(lrn): call C function to check the stack guard and return current
-    // stack state (0 = ok, positive = out of stack, negative = preempt).
-    // Then dispatch to an action depending on state, and loop.
+
+    __ push(backtrack_stackpointer());
     __ push(edi);
 
     Label retry;
-    Label stack_overflow;
 
     __ bind(&retry);
     int num_arguments = 2;
@@ -689,26 +750,57 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
     __ lea(eax, Operand(esp, -kPointerSize));
     __ mov(Operand(esp, 0 * kPointerSize), eax);
     CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments);
+    // Return value must be zero. We cannot have a stack overflow at
+    // this point, since we checked the stack on entry and haven't
+    // pushed anything since, that we haven't also popped again.
 
     ExternalReference stack_guard_limit =
         ExternalReference::address_of_stack_guard_limit();
-
-    __ or_(eax, Operand(eax));
-    __ j(not_equal, &stack_overflow);
-
+    // Check if we are still preempted.
     __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
     __ j(below_equal, &retry);
 
     __ pop(edi);
+    __ pop(backtrack_stackpointer());
     // String might have moved: Recompute esi from scratch.
-    __ mov(esi, Operand(esp, kInputBuffer));
+    __ mov(esi, Operand(ebp, kInputBuffer));
     __ mov(esi, Operand(esi, 0));
-    __ add(esi, Operand(esp, kInputEndOffset));
+    __ add(esi, Operand(ebp, kInputEndOffset));
+    SafeReturn();
+  }
+
+  // Backtrack stack overflow code.
+  if (stack_overflow_label_.is_linked()) {
+    __ bind(&stack_overflow_label_);
+    // Reached if the backtrack-stack limit has been hit.
+
+    Label grow_failed;
+    // Save registers before calling C function
+    __ push(esi);
+    __ push(edi);
+
+    // Call GrowStack(backtrack_stackpointer())
+    int num_arguments = 1;
+    FrameAlign(num_arguments);
+    __ mov(Operand(esp, 0), backtrack_stackpointer());
+    CallCFunction(FUNCTION_ADDR(&GrowStack), num_arguments);
+    // If return NULL, we have failed to grow the stack, and
+    // must exit with a stack-overflow exception.
+    __ or_(eax, Operand(eax));
+    __ j(equal, &exit_with_exception);
+    // Otherwise use return value as new stack pointer.
+    __ mov(backtrack_stackpointer(), eax);
+    // Restore saved registers and continue.
+    __ pop(edi);
+    __ pop(esi);
     SafeReturn();
+  }
 
-    __ bind(&stack_overflow);
-    // Exit with result -1 to signal thrown exception.
-    __ mov(eax, -1);
+  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(eax, EXCEPTION);
     __ jmp(&exit_label_);
   }
 
@@ -769,28 +861,32 @@ void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
 
 
 void RegExpMacroAssemblerIA32::PopCurrentPosition() {
-  __ pop(edi);
+  Pop(edi);
 }
 
 
 void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
-  __ pop(register_location(register_index));
+  Pop(eax);
+  __ mov(register_location(register_index), eax);
 }
 
 
 void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) {
-  __ push(Immediate::CodeRelativeOffset(label));
+  Push(Immediate::CodeRelativeOffset(label));
   CheckStackLimit();
 }
 
 
 void RegExpMacroAssemblerIA32::PushCurrentPosition() {
-  __ push(edi);
+  Push(edi);
 }
 
 
-void RegExpMacroAssemblerIA32::PushRegister(int register_index) {
-  __ push(register_location(register_index));
+void RegExpMacroAssemblerIA32::PushRegister(int register_index,
+                                            StackCheckFlag check_stack_limit) {
+  __ mov(eax, register_location(register_index));
+  Push(eax);
+  if (check_stack_limit) CheckStackLimit();
 }
 
 
@@ -800,7 +896,7 @@ void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) {
 
 
 void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) {
-  __ mov(esp, register_location(reg));
+  __ mov(backtrack_stackpointer(), register_location(reg));
 }
 
 
@@ -827,7 +923,7 @@ void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg,
 
 
 void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
-  __ mov(register_location(reg), esp);
+  __ mov(register_location(reg), backtrack_stackpointer());
 }
 
 
@@ -837,6 +933,38 @@ void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
 static unibrow::Mapping<unibrow::Ecma262Canonicalize> canonicalize;
 
 
+RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Execute(
+    Code* code,
+    Address* input,
+    int start_offset,
+    int end_offset,
+    int* output,
+    bool at_start) {
+  typedef int (*matcher)(Address*, int, int, int*, int, void*);
+  matcher matcher_func = FUNCTION_CAST<matcher>(code->entry());
+
+  int at_start_val = at_start ? 1 : 0;
+
+  // Ensure that the minimum stack has been allocated.
+  RegExpStack stack;
+  void* stack_top = RegExpStack::stack_top();
+
+  int result = matcher_func(input,
+                            start_offset,
+                            end_offset,
+                            output,
+                            at_start_val,
+                            stack_top);
+
+  if (result < 0 && !Top::has_pending_exception()) {
+    // We detected a stack overflow in RegExp code, but haven't created
+    // the exception yet.
+    Top::StackOverflow();
+  }
+  return (result < 0) ? EXCEPTION : (result ? SUCCESS : FAILURE);
+}
+
+
 int RegExpMacroAssemblerIA32::CaseInsensitiveCompareUC16(uc16** buffer,
                                                          int byte_offset1,
                                                          int byte_offset2,
@@ -879,11 +1007,10 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address return_address,
 
   // Prepare for possible GC.
   Handle<Code> code_handle(re_code);
-#ifdef DEBUG
-  CHECK(re_code->instruction_start() <= return_address);
-  CHECK(return_address <=
+
+  ASSERT(re_code->instruction_start() <= return_address);
+  ASSERT(return_address <=
       re_code->instruction_start() + re_code->instruction_size());
-#endif
 
   Object* result = Execution::HandleStackGuardInterrupt();
 
@@ -899,6 +1026,17 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address return_address,
 }
 
 
+Address RegExpMacroAssemblerIA32::GrowStack(Address stack_top) {
+  size_t size = RegExpStack::stack_capacity();
+  Address old_stack_end = RegExpStack::stack_top();
+  Address new_stack_end = RegExpStack::EnsureCapacity(size * 2);
+  if (new_stack_end == NULL) {
+    return NULL;
+  }
+  return stack_top + (new_stack_end - old_stack_end);
+}
+
+
 Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
   ASSERT(register_index < (1<<30));
   if (num_registers_ <= register_index) {
@@ -908,16 +1046,6 @@ Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
 }
 
 
-Register RegExpMacroAssemblerIA32::current_character() {
-  return edx;
-}
-
-
-size_t RegExpMacroAssemblerIA32::char_size() {
-  return static_cast<size_t>(mode_);
-}
-
-
 void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset,
                                              Label* on_outside_input) {
   __ cmp(edi, -cp_offset * char_size());
@@ -926,7 +1054,8 @@ void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset,
 
 
 void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
-                                                 Label* to) {
+                                                 Label* to,
+                                                 Hint hint) {
   if (condition < 0) {  // No condition
     if (to == NULL) {
       Backtrack();
@@ -936,10 +1065,10 @@ void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
     return;
   }
   if (to == NULL) {
-    __ j(condition, &backtrack_label_);
+    __ j(condition, &backtrack_label_, hint);
     return;
   }
-  __ j(condition, to);
+  __ j(condition, to, hint);
 }
 
 
@@ -952,25 +1081,60 @@ void RegExpMacroAssemblerIA32::SafeCall(Label* to) {
 
 
 void RegExpMacroAssemblerIA32::SafeReturn() {
-  __ pop(ecx);
-  __ add(Operand(ecx), Immediate(self_));
-  __ jmp(Operand(ecx));
+  __ pop(ebx);
+  __ add(Operand(ebx), Immediate(self_));
+  __ jmp(Operand(ebx));
+}
+
+
+void RegExpMacroAssemblerIA32::Push(Register source) {
+  ASSERT(!source.is(backtrack_stackpointer()));
+  // Notice: This updates flags, unlike normal Push.
+  __ sub(Operand(backtrack_stackpointer()), Immediate(kPointerSize));
+  __ mov(Operand(backtrack_stackpointer(), 0), source);
+}
+
+
+void RegExpMacroAssemblerIA32::Push(Immediate value) {
+  // Notice: This updates flags, unlike normal Push.
+  __ sub(Operand(backtrack_stackpointer()), Immediate(kPointerSize));
+  __ mov(Operand(backtrack_stackpointer(), 0), value);
+}
+
+
+void RegExpMacroAssemblerIA32::Pop(Register target) {
+  ASSERT(!target.is(backtrack_stackpointer()));
+  __ mov(target, Operand(backtrack_stackpointer(), 0));
+  // Notice: This updates flags, unlike normal Pop.
+  __ add(Operand(backtrack_stackpointer()), Immediate(kPointerSize));
+}
+
+
+void RegExpMacroAssemblerIA32::CheckPreemption() {
+  // Check for preemption.
+  Label no_preempt;
+  ExternalReference stack_guard_limit =
+      ExternalReference::address_of_stack_guard_limit();
+  __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
+  __ j(above, &no_preempt, taken);
+
+  SafeCall(&check_preempt_label_);
+
+  __ bind(&no_preempt);
 }
 
 
 void RegExpMacroAssemblerIA32::CheckStackLimit() {
   if (FLAG_check_stack) {
-    // Check for preemption first.
-    Label no_preempt;
-    // Check for preemption.
-    ExternalReference stack_guard_limit =
-        ExternalReference::address_of_stack_guard_limit();
-    __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
-    __ j(above, &no_preempt, taken);
+    Label no_stack_overflow;
+    ExternalReference stack_limit =
+        ExternalReference::address_of_regexp_stack_limit();
+    __ cmp(backtrack_stackpointer(), Operand::StaticVariable(stack_limit));
+    __ j(above, &no_stack_overflow);
 
-    SafeCall(&check_preempt_label_);
+    SafeCall(&stack_overflow_label_);
 
-    __ bind(&no_preempt);
+    __ bind(&no_stack_overflow);
   }
 }
 
index 2f716d6..1fdbf98 100644 (file)
@@ -38,6 +38,7 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
 
   RegExpMacroAssemblerIA32(Mode mode, int registers_to_save);
   virtual ~RegExpMacroAssemblerIA32();
+  virtual int stack_limit_slack();
   virtual void AdvanceCurrentPosition(int by);
   virtual void AdvanceRegister(int reg, int by);
   virtual void Backtrack();
@@ -53,6 +54,8 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
                                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);
@@ -96,7 +99,8 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
   virtual void PopRegister(int register_index);
   virtual void PushBacktrack(Label* label);
   virtual void PushCurrentPosition();
-  virtual void PushRegister(int register_index);
+  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);
@@ -104,26 +108,15 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
   virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
   virtual void WriteStackPointerToRegister(int reg);
 
-  template <typename T>
-  static inline Result Execute(Code* code,
-                               T** input,
-                               int start_offset,
-                               int end_offset,
-                               int* output,
-                               bool at_start) {
-    typedef int (*matcher)(T**, int, int, int*, int);
-    matcher matcher_func = FUNCTION_CAST<matcher>(code->entry());
-    int at_start_val = at_start ? 1 : 0;
-    int result = matcher_func(input,
-                              start_offset,
-                              end_offset,
-                              output,
-                              at_start_val);
-    return (result < 0) ? EXCEPTION : (result ? SUCCESS : FAILURE);
-  }
+  static Result Execute(Code* code,
+                        Address* input,
+                        int start_offset,
+                        int end_offset,
+                        int* output,
+                        bool at_start);
 
  private:
-  // Offsets from ebp of arguments to function.
+  // Offsets from ebp of arguments to function and stored registers.
   static const int kBackup_ebx = sizeof(uint32_t);
   static const int kBackup_edi = kBackup_ebx + sizeof(uint32_t);
   static const int kBackup_esi = kBackup_edi + sizeof(uint32_t);
@@ -133,24 +126,30 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
   static const int kInputEndOffset = kInputStartOffset + sizeof(uint32_t);
   static const int kRegisterOutput = kInputEndOffset + sizeof(uint32_t);
   static const int kAtStart = kRegisterOutput + sizeof(uint32_t);
+  static const int kStackHighEnd = kAtStart + sizeof(uint32_t);
 
   // Initial size of code buffer.
   static const size_t kRegExpCodeSize = 1024;
   // Initial size of constant buffers allocated during compilation.
   static const int kRegExpConstantsSize = 256;
-  // Only unroll loops up to this length. TODO(lrn): Actually use this.
+  // Only unroll loops up to this length.
   static const int kMaxInlineStringTests = 32;
 
   // Compares two-byte strings case insensitively.
+  // Called from generated RegExp code.
   static int CaseInsensitiveCompareUC16(uc16** buffer,
                                         int byte_offset1,
                                         int byte_offset2,
                                         size_t byte_length);
 
-  void LoadCurrentCharacterUnchecked(int cp_offset, int characters);
+  // 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);
 
-  // Adds code that checks whether preemption has been requested
-  // (and checks if we have hit the stack limit too).
+  // Check whether preemption has been requested.
+  void CheckPreemption();
+
+  // Check whether we are exceeding the stack limit on the backtrack stack.
   void CheckStackLimit();
 
   // Called from RegExp if the stack-guard is triggered.
@@ -158,6 +157,12 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
   // returning.
   static int CheckStackGuardState(Address return_address, Code* re_code);
 
+  // Called from RegExp if the backtrack stack limit is hit.
+  // Tries to expand the stack. Returns the new stack-top pointer if
+  // successful, or 0 if unable to grow the stack.
+  // This function must not trigger a garbage collection.
+  static Address GrowStack(Address stack_top);
+
   // Checks whether the given offset from the current position is before
   // the end of the string.
   void CheckPosition(int cp_offset, Label* on_outside_input);
@@ -166,14 +171,18 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
   Operand register_location(int register_index);
 
   // The register containing the current character after LoadCurrentCharacter.
-  Register current_character();
+  inline Register current_character() { return edx; }
+
+  // The register containing the backtrack stack top. Provides a meaningful
+  // name to the register.
+  inline Register backtrack_stackpointer() { return ecx; }
 
   // Byte size of chars in the string to match (decided by the Mode argument)
-  size_t char_size();
+  inline size_t char_size() { return static_cast<size_t>(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);
+  void BranchOrBacktrack(Condition condition, Label* to, Hint hint = no_hint);
 
   // Load the address of a "constant buffer" (a slice of a byte array)
   // into a register. The address is computed from the ByteArray* address
@@ -182,30 +191,50 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
 
   // 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)
-  void SafeCall(Label* to);
-  void SafeReturn();
+  inline void SafeCall(Label* to);
+  inline void SafeReturn();
+
+  // Pushes the value of a register on the backtrack stack. Decrements the
+  // stack pointer (ecx) by a word size and stores the register's value there.
+  inline void Push(Register source);
+
+  // Pushes a value on the backtrack stack. Decrements the stack pointer (ecx)
+  // by a word size and stores the value there.
+  inline void Push(Immediate value);
+
+  // Pops a value from the backtrack stack. Reads the word at the stack pointer
+  // (ecx) 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, arguments must be stored in esp[0], esp[4],
   // etc., not pushed. The argument count assumes all arguments are word sized.
-  void FrameAlign(int num_arguments);
+  // Some compilers/platforms require the stack to be aligned when calling
+  // C++ code.
+  inline void FrameAlign(int num_arguments);
+
   // 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, since that might move the code and invalidate the return
-  // address
-  void CallCFunction(Address function_address, int num_arguments);
+  // address (unless this is somehow accounted for).
+  inline void CallCFunction(Address function_address, int num_arguments);
 
   MacroAssembler* masm_;
+
   // Constant buffer provider. Allocates external storage for storing
   // constants.
   ByteArrayProvider constants_;
+
   // Which mode to generate code for (ASCII or UTF16).
   Mode mode_;
+
   // One greater than maximal register index actually used.
   int num_registers_;
+
   // Number of registers to output at the end (the saved registers
   // are always 0..num_saved_registers_-1)
   int num_saved_registers_;
+
   // Labels used internally.
   Label entry_label_;
   Label start_label_;
@@ -213,6 +242,8 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
   Label backtrack_label_;
   Label exit_label_;
   Label check_preempt_label_;
+  Label stack_overflow_label_;
+
   // Handle used to represent the generated code object itself.
   Handle<Object> self_;
 };
index e2bed27..d962a73 100644 (file)
@@ -89,7 +89,9 @@ void RegExpMacroAssemblerIrregexp::PopRegister(int register_index) {
 }
 
 
-void RegExpMacroAssemblerIrregexp::PushRegister(int register_index) {
+void RegExpMacroAssemblerIrregexp::PushRegister(
+    int register_index,
+    StackCheckFlag check_stack_limit) {
   ASSERT(register_index >= 0);
   Emit(BC_PUSH_REGISTER);
   Emit(register_index);
index 1167b1d..b2fba37 100644 (file)
@@ -48,6 +48,8 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
   // upon destruction of the assembler.
   explicit RegExpMacroAssemblerIrregexp(Vector<byte>);
   virtual ~RegExpMacroAssemblerIrregexp();
+  // The byte-code interpreter checks on each push anyway.
+  virtual int stack_limit_slack() { return 1; }
   virtual void Bind(Label* label);
   virtual void EmitOrLink(Label* label);
   virtual void AdvanceCurrentPosition(int by);  // Signed cp change.
@@ -59,7 +61,8 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
   virtual void Succeed();
   virtual void Fail();
   virtual void PopRegister(int register_index);
-  virtual void PushRegister(int register_index);
+  virtual void PushRegister(int register_index,
+                            StackCheckFlag check_stack_limit);
   virtual void AdvanceRegister(int reg, int by);  // r[reg] += by.
   virtual void SetRegister(int register_index, int to);
   virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
index 2eb7ec5..c733a2f 100644 (file)
@@ -95,7 +95,8 @@ void RegExpMacroAssemblerTracer::GoTo(Label* label) {
 
 
 void RegExpMacroAssemblerTracer::PushBacktrack(Label* label) {
-  PrintF(" PushBacktrack(label[%08x]);\n", label);
+  PrintF(" PushBacktrack(label[%08x]);\n",
+         label);
   assembler_->PushBacktrack(label);
 }
 
@@ -118,9 +119,13 @@ void RegExpMacroAssemblerTracer::PopRegister(int register_index) {
 }
 
 
-void RegExpMacroAssemblerTracer::PushRegister(int register_index) {
-  PrintF(" PushRegister(register=%d);\n", register_index);
-  assembler_->PushRegister(register_index);
+void RegExpMacroAssemblerTracer::PushRegister(
+    int register_index,
+    StackCheckFlag check_stack_limit) {
+  PrintF(" PushRegister(register=%d, %s);\n",
+         register_index,
+         check_stack_limit ? "check stack limit" : "");
+  assembler_->PushRegister(register_index, check_stack_limit);
 }
 
 
index f5b8851..7a7a401 100644 (file)
@@ -35,6 +35,7 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
  public:
   explicit RegExpMacroAssemblerTracer(RegExpMacroAssembler* assembler);
   virtual ~RegExpMacroAssemblerTracer();
+  virtual int stack_limit_slack() { return assembler_->stack_limit_slack(); }
 
   virtual void AdvanceCurrentPosition(int by);  // Signed cp change.
   virtual void AdvanceRegister(int reg, int by);  // r[reg] += by.
@@ -98,7 +99,8 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
   virtual void PopRegister(int register_index);
   virtual void PushBacktrack(Label* label);
   virtual void PushCurrentPosition();
-  virtual void PushRegister(int register_index);
+  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);
index 34925f5..913ac64 100644 (file)
@@ -68,10 +68,11 @@ ArraySlice ByteArrayProvider::GetBuffer(unsigned int size,
   return ArraySlice(current_byte_array_, free_offset);
 }
 
+
 template <typename T>
 ArraySlice ByteArrayProvider::GetBuffer(Vector<T> values) {
   ArraySlice slice = GetBuffer(values.length(), sizeof(T));
   memcpy(slice.location(), values.start(), values.length() * sizeof(T));
   return slice;
 }
-} }
+} }  // namespace v8::internal
index 878a297..4b76cab 100644 (file)
@@ -30,7 +30,6 @@
 
 namespace v8 { namespace internal {
 
-
 struct DisjunctDecisionRow {
   RegExpCharacterClass cc;
   Label* on_match;
@@ -42,12 +41,24 @@ class RegExpMacroAssembler {
   enum IrregexpImplementation {
     kIA32Implementation,
     kARMImplementation,
-    kBytecodeImplementation};
+    kBytecodeImplementation
+  };
+
+  enum StackCheckFlag {
+    kNoStackLimitCheck = false,
+    kCheckStackLimit = true
+  };
 
   RegExpMacroAssembler();
   virtual ~RegExpMacroAssembler();
+  // The maximal number of pushes between stack checks. Users must supply
+  // 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 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
+  // stack by an earlier PushBacktrack(Label*).
   virtual void Backtrack() = 0;
   virtual void Bind(Label* label) = 0;
   // Check the current character against a bitmap.  The range of the current
@@ -145,9 +156,12 @@ class RegExpMacroAssembler {
                                     int characters = 1) = 0;
   virtual void PopCurrentPosition() = 0;
   virtual void PopRegister(int register_index) = 0;
+  // Pushes the label on the backtrack stack, so that a following Backtrack
+  // will go to this label. Always checks the backtrack stack limit.
   virtual void PushBacktrack(Label* label) = 0;
   virtual void PushCurrentPosition() = 0;
-  virtual void PushRegister(int register_index) = 0;
+  virtual void PushRegister(int register_index,
+                            StackCheckFlag check_stack_limit) = 0;
   virtual void ReadCurrentPositionFromRegister(int reg) = 0;
   virtual void ReadStackPointerFromRegister(int reg) = 0;
   virtual void SetRegister(int register_index, int to) = 0;
diff --git a/src/regexp-stack.cc b/src/regexp-stack.cc
new file mode 100644 (file)
index 0000000..05daa58
--- /dev/null
@@ -0,0 +1,94 @@
+// 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:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+#include "top.h"
+#include "regexp-stack.h"
+
+namespace v8 { namespace internal {
+
+RegExpStack::RegExpStack() {
+  // Initialize, if not already initialized.
+  RegExpStack::EnsureCapacity(0);
+}
+
+
+RegExpStack::~RegExpStack() {
+  // Reset the buffer if it has grown.
+  RegExpStack::Reset();
+}
+
+
+char* RegExpStack::ArchiveStack(char* to) {
+  size_t size = sizeof(thread_local_);
+  memcpy(reinterpret_cast<void*>(to),
+         &thread_local_,
+         size);
+  thread_local_ = ThreadLocal();
+  return to + size;
+}
+
+
+char* RegExpStack::RestoreStack(char* from) {
+  size_t size = sizeof(thread_local_);
+  memcpy(&thread_local_, reinterpret_cast<void*>(from), size);
+  return from + size;
+}
+
+
+void RegExpStack::Reset() {
+  if (thread_local_.memory_size_ > kMinimumStackSize) {
+    DeleteArray(thread_local_.memory_);
+    thread_local_ = ThreadLocal();
+  }
+}
+
+
+Address RegExpStack::EnsureCapacity(size_t size) {
+  if (size > kMaximumStackSize) return NULL;
+  if (size < kMinimumStackSize) size = kMinimumStackSize;
+  if (thread_local_.memory_size_ < size) {
+    Address new_memory = NewArray<byte>(size);
+    if (thread_local_.memory_size_ > 0) {
+      // Copy original memory into top of new memory.
+      memcpy(reinterpret_cast<void*>(
+          new_memory + size - thread_local_.memory_size_),
+             reinterpret_cast<void*>(thread_local_.memory_),
+             thread_local_.memory_size_);
+      DeleteArray(thread_local_.memory_);
+    }
+    thread_local_.memory_ = new_memory;
+    thread_local_.memory_size_ = size;
+    thread_local_.limit_ = new_memory + kStackLimitSlack * kPointerSize;
+  }
+  return thread_local_.memory_ + thread_local_.memory_size_;
+}
+
+
+RegExpStack::ThreadLocal RegExpStack::thread_local_;
+
+}}  // namespace v8::internal
diff --git a/src/regexp-stack.h b/src/regexp-stack.h
new file mode 100644 (file)
index 0000000..43f8f3d
--- /dev/null
@@ -0,0 +1,106 @@
+// 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:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef REGEXP_STACK_H_
+#define REGEXP_STACK_H_
+
+namespace v8 { namespace internal {
+
+// Maintains a per-v8thread stack area that can be used by irregexp
+// implementation for its backtracking stack.
+// Since there is only one stack area, the Irregexp implementation is not
+// re-entrant. I.e., no regular expressions may be executed in the same thread
+// during a preempted Irregexp execution.
+class RegExpStack {
+ public:
+  // Number of allocated locations on the stack below the limit.
+  // No sequence of pushes must be longer that this without doing a stack-limit
+  // check.
+  static const int kStackLimitSlack = 32;
+
+  // Create and delete an instance to control the life-time of a growing stack.
+  RegExpStack();  // Initializes the stack memory area if necessary.
+  ~RegExpStack();  // Releases the stack if it has grown.
+
+  // Gives the top of the memory used as stack.
+  static Address stack_top() {
+    ASSERT(thread_local_.memory_size_ != 0);
+    return thread_local_.memory_ + thread_local_.memory_size_;
+  }
+
+  // The total size of the memory allocated for the stack.
+  static size_t stack_capacity() { return thread_local_.memory_size_; }
+
+  // If the stack pointer gets below the limit, we should react and
+  // either grow the stack or report an out-of-stack exception.
+  // There is only a limited number of locations below the stack limit,
+  // so users of the stack should check the stack limit during any
+  // sequence of pushes longer that this.
+  static Address* limit_address() { return &(thread_local_.limit_); }
+
+  // Ensures that there is a memory area with at least the specified size.
+  // If passing zero, the default/minimum size buffer is allocated.
+  static Address EnsureCapacity(size_t size);
+
+  // Thread local archiving.
+  static size_t ArchiveSpacePerThread() { return sizeof(thread_local_); }
+  static char* ArchiveStack(char* to);
+  static char* RestoreStack(char* from);
+
+ private:
+  // Artificial limit used when no memory has been allocated.
+  static const uint32_t kMemoryTop = 0xffffffff;
+
+  // Minimal size of allocated stack area.
+  static const size_t kMinimumStackSize = 1 * KB;
+
+  // Maximal size of allocated stack area.
+  static const size_t kMaximumStackSize = 256 * KB;
+
+  // Structure holding the allocated memory, size and limit.
+  struct ThreadLocal {
+    ThreadLocal()
+        : memory_(NULL),
+          memory_size_(0),
+          limit_(reinterpret_cast<Address>(kMemoryTop)) {}
+    // If memory_size_ > 0 then memory_ must be non-NULL.
+    Address memory_;
+    size_t memory_size_;
+    Address limit_;
+  };
+
+  // Resets the buffer if it has grown beyond the default/minimum size.
+  // After this, the buffer is either the default size, or it is empty, so
+  // you have to call EnsureCapacity before using it again.
+  static void Reset();
+
+  static ThreadLocal thread_local_;
+};
+
+}}  // namespace v8::internal
+
+#endif /* REGEXP_STACK_H_ */
index 6b7533b..0a6c7c1 100644 (file)
@@ -31,6 +31,7 @@
 #include "debug.h"
 #include "execution.h"
 #include "v8threads.h"
+#include "regexp-stack.h"
 
 namespace v8 {
 
@@ -125,6 +126,7 @@ bool ThreadManager::RestoreThread() {
   from = Top::RestoreThread(from);
   from = Debug::RestoreDebug(from);
   from = StackGuard::RestoreStackGuard(from);
+  from = RegExpStack::RestoreStack(from);
   Thread::SetThreadLocal(thread_state_key, NULL);
   state->Unlink();
   state->LinkInto(ThreadState::FREE_LIST);
@@ -149,7 +151,8 @@ static int ArchiveSpacePerThread() {
   return HandleScopeImplementer::ArchiveSpacePerThread() +
                             Top::ArchiveSpacePerThread() +
                           Debug::ArchiveSpacePerThread() +
-                     StackGuard::ArchiveSpacePerThread();
+                     StackGuard::ArchiveSpacePerThread() +
+                    RegExpStack::ArchiveSpacePerThread();
 }
 
 
@@ -230,6 +233,7 @@ void ThreadManager::EagerlyArchiveThread() {
   to = Top::ArchiveThread(to);
   to = Debug::ArchiveDebug(to);
   to = StackGuard::ArchiveStackGuard(to);
+  to = RegExpStack::ArchiveStack(to);
   lazily_archived_thread_.Initialize(ThreadHandle::INVALID);
   lazily_archived_thread_state_ = NULL;
 }
index 89ea9ab..bb94d35 100644 (file)
@@ -598,7 +598,7 @@ TEST(MacroAssembler) {
   foo_chars[2] = 'o';
   Vector<const uc16> foo(foo_chars, 3);
   m.SetRegister(4, 42);
-  m.PushRegister(4);
+  m.PushRegister(4, RegExpMacroAssembler::kNoStackLimitCheck);
   m.AdvanceRegister(4, 42);
   m.GoTo(&start);
   m.Fail();
@@ -666,6 +666,40 @@ class ContextInitializer {
   v8::internal::StackGuard stack_guard_;
 };
 
+// Helper functions for calling the Execute method.
+template <typename T>
+static RegExpMacroAssemblerIA32::Result ExecuteIA32(Code* code,
+                                                    const T** input,
+                                                    int start_offset,
+                                                    int end_offset,
+                                                    int* captures,
+                                                    bool at_start) {
+  return RegExpMacroAssemblerIA32::Execute(
+      code,
+      reinterpret_cast<Address*>(
+          reinterpret_cast<void*>(const_cast<T**>(input))),
+      start_offset,
+      end_offset,
+      captures,
+      at_start);
+}
+
+template <typename T>
+static RegExpMacroAssemblerIA32::Result ExecuteIA32(Code* code,
+                                                    T** input,
+                                                    int start_offset,
+                                                    int end_offset,
+                                                    int* captures,
+                                                    bool at_start) {
+  return RegExpMacroAssemblerIA32::Execute(
+      code,
+      reinterpret_cast<Address*>(reinterpret_cast<void*>(input)),
+      start_offset,
+      end_offset,
+      captures,
+      at_start);
+}
+
 
 TEST(MacroAssemblerIA32Success) {
   v8::V8::Initialize();
@@ -687,12 +721,12 @@ TEST(MacroAssemblerIA32Success) {
   int end_offset = start_offset + seq_input->length();
 
   RegExpMacroAssemblerIA32::Result result =
-      RegExpMacroAssemblerIA32::Execute(*code,
-                                        seq_input.location(),
-                                        start_offset,
-                                        end_offset,
-                                        captures,
-                                        true);
+      ExecuteIA32(*code,
+                  seq_input.location(),
+                  start_offset,
+                  end_offset,
+                  captures,
+                  true);
 
   CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
   CHECK_EQ(-1, captures[0]);
@@ -732,12 +766,12 @@ TEST(MacroAssemblerIA32Simple) {
   int end_offset = start_offset + seq_input->length();
 
   RegExpMacroAssemblerIA32::Result result =
-      RegExpMacroAssemblerIA32::Execute(*code,
-                                        seq_input.location(),
-                                        start_offset,
-                                        end_offset,
-                                        captures,
-                                        true);
+      ExecuteIA32(*code,
+                  seq_input.location(),
+                  start_offset,
+                  end_offset,
+                  captures,
+                  true);
 
   CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
   CHECK_EQ(0, captures[0]);
@@ -751,12 +785,12 @@ TEST(MacroAssemblerIA32Simple) {
   start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
   end_offset = start_offset + seq_input->length();
 
-  result = RegExpMacroAssemblerIA32::Execute(*code,
-                                             seq_input.location(),
-                                             start_offset,
-                                             end_offset,
-                                             captures,
-                                             true);
+  result = ExecuteIA32(*code,
+                       seq_input.location(),
+                       start_offset,
+                       end_offset,
+                       captures,
+                       true);
 
   CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result);
 }
@@ -794,12 +828,12 @@ TEST(MacroAssemblerIA32SimpleUC16) {
   int end_offset = start_offset + seq_input->length() * sizeof(uc16);
 
   RegExpMacroAssemblerIA32::Result result =
-      RegExpMacroAssemblerIA32::Execute(*code,
-                                        seq_input.location(),
-                                        start_offset,
-                                        end_offset,
-                                        captures,
-                                        true);
+      ExecuteIA32(*code,
+                  seq_input.location(),
+                  start_offset,
+                  end_offset,
+                  captures,
+                  true);
 
   CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
   CHECK_EQ(0, captures[0]);
@@ -814,12 +848,12 @@ TEST(MacroAssemblerIA32SimpleUC16) {
   start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
   end_offset = start_offset + seq_input->length() * sizeof(uc16);
 
-  result = RegExpMacroAssemblerIA32::Execute(*code,
-                                             seq_input.location(),
-                                             start_offset,
-                                             end_offset,
-                                             captures,
-                                             true);
+  result = ExecuteIA32(*code,
+                       seq_input.location(),
+                       start_offset,
+                       end_offset,
+                       captures,
+                       true);
 
   CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result);
 }
@@ -853,12 +887,12 @@ TEST(MacroAssemblerIA32Backtrack) {
   int end_offset = start_offset + seq_input->length();
 
   RegExpMacroAssemblerIA32::Result result =
-      RegExpMacroAssemblerIA32::Execute(*code,
-                                        seq_input.location(),
-                                        start_offset,
-                                        end_offset,
-                                        NULL,
-                                        true);
+      ExecuteIA32(*code,
+                  seq_input.location(),
+                  start_offset,
+                  end_offset,
+                  NULL,
+                  true);
 
   CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result);
 }
@@ -897,12 +931,12 @@ TEST(MacroAssemblerIA32BackReferenceASCII) {
 
   int output[3];
   RegExpMacroAssemblerIA32::Result result =
-      RegExpMacroAssemblerIA32::Execute(*code,
-                                        seq_input.location(),
-                                        start_offset,
-                                        end_offset,
-                                        output,
-                                        true);
+      ExecuteIA32(*code,
+                  seq_input.location(),
+                  start_offset,
+                  end_offset,
+                  output,
+                  true);
 
   CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
   CHECK_EQ(0, output[0]);
@@ -947,12 +981,12 @@ TEST(MacroAssemblerIA32BackReferenceUC16) {
 
   int output[3];
   RegExpMacroAssemblerIA32::Result result =
-      RegExpMacroAssemblerIA32::Execute(*code,
-                                        seq_input.location(),
-                                        start_offset,
-                                        end_offset,
-                                        output,
-                                        true);
+      ExecuteIA32(*code,
+                  seq_input.location(),
+                  start_offset,
+                  end_offset,
+                  output,
+                  true);
 
   CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
   CHECK_EQ(0, output[0]);
@@ -1000,22 +1034,22 @@ TEST(MacroAssemblerIA32AtStart) {
   int end_offset = start_offset + seq_input->length();
 
   RegExpMacroAssemblerIA32::Result result =
-      RegExpMacroAssemblerIA32::Execute(*code,
-                                        seq_input.location(),
-                                        start_offset,
-                                        end_offset,
-                                        NULL,
-                                        true);
+      ExecuteIA32(*code,
+                  seq_input.location(),
+                  start_offset,
+                  end_offset,
+                  NULL,
+                  true);
 
   CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
 
   start_offset += 3;
-  result = RegExpMacroAssemblerIA32::Execute(*code,
-                                              seq_input.location(),
-                                              start_offset,
-                                              end_offset,
-                                              NULL,
-                                              false);
+  result = ExecuteIA32(*code,
+                       seq_input.location(),
+                       start_offset,
+                       end_offset,
+                       NULL,
+                       false);
 
   CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
 }
@@ -1065,12 +1099,12 @@ TEST(MacroAssemblerIA32BackRefNoCase) {
 
   int output[4];
   RegExpMacroAssemblerIA32::Result result =
-      RegExpMacroAssemblerIA32::Execute(*code,
-                                        seq_input.location(),
-                                        start_offset,
-                                        end_offset,
-                                        output,
-                                        true);
+      ExecuteIA32(*code,
+                  seq_input.location(),
+                  start_offset,
+                  end_offset,
+                  output,
+                  true);
 
   CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
   CHECK_EQ(0, output[0]);
@@ -1094,13 +1128,13 @@ TEST(MacroAssemblerIA32Registers) {
   Label fail;
   Label backtrack;
   m.WriteCurrentPositionToRegister(out1, 0);  // Output: [0]
-  m.PushRegister(out1);
+  m.PushRegister(out1, RegExpMacroAssembler::kNoStackLimitCheck);
   m.PushBacktrack(&backtrack);
   m.WriteStackPointerToRegister(sp);
   // Fill stack and registers
   m.AdvanceCurrentPosition(2);
   m.WriteCurrentPositionToRegister(out1, 0);
-  m.PushRegister(out1);
+  m.PushRegister(out1, RegExpMacroAssembler::kNoStackLimitCheck);
   m.PushBacktrack(&fail);
   // Drop backtrack stack frames.
   m.ReadStackPointerFromRegister(sp);
@@ -1135,8 +1169,8 @@ TEST(MacroAssemblerIA32Registers) {
 
   Label loop3;
   Label exit_loop3;
-  m.PushRegister(out4);
-  m.PushRegister(out4);
+  m.PushRegister(out4, RegExpMacroAssembler::kNoStackLimitCheck);
+  m.PushRegister(out4, RegExpMacroAssembler::kNoStackLimitCheck);
   m.ReadCurrentPositionFromRegister(out3);
   m.Bind(&loop3);
   m.AdvanceCurrentPosition(1);
@@ -1166,12 +1200,12 @@ TEST(MacroAssemblerIA32Registers) {
 
   int output[5];
   RegExpMacroAssemblerIA32::Result result =
-      RegExpMacroAssemblerIA32::Execute(*code,
-                                        seq_input.location(),
-                                        start_offset,
-                                        end_offset,
-                                        output,
-                                        true);
+      ExecuteIA32(*code,
+                  seq_input.location(),
+                  start_offset,
+                  end_offset,
+                  output,
+                  true);
 
   CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
   CHECK_EQ(0, output[0]);
@@ -1207,12 +1241,12 @@ TEST(MacroAssemblerIA32StackOverflow) {
   int end_offset = start_offset + seq_input->length();
 
   RegExpMacroAssemblerIA32::Result result =
-      RegExpMacroAssemblerIA32::Execute(*code,
-                                        seq_input.location(),
-                                        start_offset,
-                                        end_offset,
-                                        NULL,
-                                        true);
+      ExecuteIA32(*code,
+                  seq_input.location(),
+                  start_offset,
+                  end_offset,
+                  NULL,
+                  true);
 
   CHECK_EQ(RegExpMacroAssemblerIA32::EXCEPTION, result);
   CHECK(Top::has_pending_exception());
@@ -1220,6 +1254,56 @@ TEST(MacroAssemblerIA32StackOverflow) {
 }
 
 
+TEST(MacroAssemblerIA32LotsOfRegisters) {
+  v8::V8::Initialize();
+  ContextInitializer initializer;
+
+  RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 2);
+
+  // At least 2048, to ensure the allocated space for registers
+  // span one full page.
+  const int large_number = 8000;
+  m.WriteCurrentPositionToRegister(large_number, 42);
+  m.WriteCurrentPositionToRegister(0, 0);
+  m.WriteCurrentPositionToRegister(1, 1);
+  Label done;
+  m.CheckNotBackReference(0, &done);  // Performs a system-stack push.
+  m.Bind(&done);
+  m.PushRegister(large_number, RegExpMacroAssembler::kNoStackLimitCheck);
+  m.PopRegister(1);
+  m.Succeed();
+
+  Handle<String> source =
+      Factory::NewStringFromAscii(CStrVector("<huge register space test>"));
+  Handle<Object> code_object = m.GetCode(source);
+  Handle<Code> code = Handle<Code>::cast(code_object);
+
+  // String long enough for test (content doesn't matter).
+  Handle<String> input =
+      Factory::NewStringFromAscii(CStrVector("sample text"));
+  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();
+
+  int captures[2];
+  RegExpMacroAssemblerIA32::Result result =
+      ExecuteIA32(*code,
+                  seq_input.location(),
+                  start_offset,
+                  end_offset,
+                  captures,
+                  true);
+
+  CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
+  CHECK_EQ(0, captures[0]);
+  CHECK_EQ(42, captures[1]);
+
+  Top::clear_pending_exception();
+}
+
+
+
 #endif  // !defined ARM
 
 TEST(AddInverseToTable) {
index 558b026..7340fe5 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\regexp-stack.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\assembler.cc"
                                >
                        </File>
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\regexp-stack.cc"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\rewriter.cc"
                                >
                        </File>
index 7f1adb3..3462835 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\regexp-stack.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\regexp-macro-assembler-irregexp-inl.h"
                                >
                        </File>
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\regexp-stack.cc"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\rewriter.cc"
                                >
                        </File>