Commit 21d28657 authored by lrn@chromium.org's avatar lrn@chromium.org

Separately growing stack for irregexp ia32 backtrack stack.


git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1053 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent cb94595c
...@@ -44,11 +44,11 @@ SOURCES = { ...@@ -44,11 +44,11 @@ SOURCES = {
'interpreter-irregexp.cc', 'jsregexp.cc', 'log.cc', 'mark-compact.cc', 'interpreter-irregexp.cc', 'jsregexp.cc', 'log.cc', 'mark-compact.cc',
'messages.cc', 'objects.cc', 'parser.cc', 'property.cc', 'messages.cc', 'objects.cc', 'parser.cc', 'property.cc',
'regexp-macro-assembler.cc', 'regexp-macro-assembler-irregexp.cc', 'regexp-macro-assembler.cc', 'regexp-macro-assembler-irregexp.cc',
'rewriter.cc', 'runtime.cc', 'scanner.cc', 'scopeinfo.cc', 'scopes.cc', 'regexp-stack.cc', 'rewriter.cc', 'runtime.cc', 'scanner.cc',
'serialize.cc', 'snapshot-common.cc', 'spaces.cc', 'string-stream.cc', 'scopeinfo.cc', 'scopes.cc', 'serialize.cc', 'snapshot-common.cc',
'stub-cache.cc', 'token.cc', 'top.cc', 'unicode.cc', 'usage-analyzer.cc', 'spaces.cc', 'string-stream.cc', 'stub-cache.cc', 'token.cc', 'top.cc',
'utils.cc', 'v8-counters.cc', 'v8.cc', 'v8threads.cc', 'variables.cc', 'unicode.cc', 'usage-analyzer.cc', 'utils.cc', 'v8-counters.cc', 'v8.cc',
'zone.cc' 'v8threads.cc', 'variables.cc', 'zone.cc'
], ],
'arch:arm': ['assembler-arm.cc', 'builtins-arm.cc', 'codegen-arm.cc', 'arch:arm': ['assembler-arm.cc', 'builtins-arm.cc', 'codegen-arm.cc',
'cpu-arm.cc', 'debug-arm.cc', 'disasm-arm.cc', 'frames-arm.cc', 'cpu-arm.cc', 'debug-arm.cc', 'disasm-arm.cc', 'frames-arm.cc',
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "runtime.h" #include "runtime.h"
#include "serialize.h" #include "serialize.h"
#include "stub-cache.h" #include "stub-cache.h"
#include "regexp-stack.h"
namespace v8 { namespace internal { namespace v8 { namespace internal {
...@@ -551,6 +552,11 @@ ExternalReference ExternalReference::address_of_stack_guard_limit() { ...@@ -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() { ExternalReference ExternalReference::debug_break() {
return ExternalReference(FUNCTION_ADDR(Debug::Break)); return ExternalReference(FUNCTION_ADDR(Debug::Break));
} }
......
...@@ -442,6 +442,9 @@ class ExternalReference BASE_EMBEDDED { ...@@ -442,6 +442,9 @@ class ExternalReference BASE_EMBEDDED {
// Static variable StackGuard::address_of_limit() // Static variable StackGuard::address_of_limit()
static ExternalReference address_of_stack_guard_limit(); static ExternalReference address_of_stack_guard_limit();
// Static variable RegExpStack::limit_address()
static ExternalReference address_of_regexp_stack_limit();
// Function Debug::Break() // Function Debug::Break()
static ExternalReference debug_break(); static ExternalReference debug_break();
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "regexp-macro-assembler.h" #include "regexp-macro-assembler.h"
#include "regexp-macro-assembler-tracer.h" #include "regexp-macro-assembler-tracer.h"
#include "regexp-macro-assembler-irregexp.h" #include "regexp-macro-assembler-irregexp.h"
#include "regexp-stack.h"
#ifdef ARM #ifdef ARM
#include "regexp-macro-assembler-arm.h" #include "regexp-macro-assembler-arm.h"
...@@ -913,7 +914,7 @@ Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<FixedArray> irregexp, ...@@ -913,7 +914,7 @@ Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<FixedArray> irregexp,
} }
res = RegExpMacroAssemblerIA32::Execute( res = RegExpMacroAssemblerIA32::Execute(
*code, *code,
&address, const_cast<Address*>(&address),
start_offset << char_size_shift, start_offset << char_size_shift,
end_offset << char_size_shift, end_offset << char_size_shift,
offsets_vector, offsets_vector,
...@@ -925,7 +926,7 @@ Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<FixedArray> irregexp, ...@@ -925,7 +926,7 @@ Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<FixedArray> irregexp,
int byte_offset = char_address - reinterpret_cast<Address>(*subject); int byte_offset = char_address - reinterpret_cast<Address>(*subject);
res = RegExpMacroAssemblerIA32::Execute( res = RegExpMacroAssemblerIA32::Execute(
*code, *code,
subject.location(), reinterpret_cast<Address*>(subject.location()),
byte_offset + (start_offset << char_size_shift), byte_offset + (start_offset << char_size_shift),
byte_offset + (end_offset << char_size_shift), byte_offset + (end_offset << char_size_shift),
offsets_vector, offsets_vector,
...@@ -1347,8 +1348,18 @@ int GenerationVariant::FindAffectedRegisters(OutSet* affected_registers) { ...@@ -1347,8 +1348,18 @@ int GenerationVariant::FindAffectedRegisters(OutSet* affected_registers) {
void GenerationVariant::PushAffectedRegisters(RegExpMacroAssembler* assembler, void GenerationVariant::PushAffectedRegisters(RegExpMacroAssembler* assembler,
int max_register, int max_register,
OutSet& affected_registers) { OutSet& affected_registers) {
for (int reg = 0; reg <= max_register; reg++) { // Stay safe and check every half times the limit.
if (affected_registers.Get(reg)) assembler->PushRegister(reg); // (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);
}
} }
} }
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "unicode.h" #include "unicode.h"
#include "log.h" #include "log.h"
#include "ast.h" #include "ast.h"
#include "regexp-stack.h"
#include "macro-assembler.h" #include "macro-assembler.h"
#include "regexp-macro-assembler.h" #include "regexp-macro-assembler.h"
#include "macro-assembler-ia32.h" #include "macro-assembler-ia32.h"
...@@ -46,12 +47,15 @@ namespace v8 { namespace internal { ...@@ -46,12 +47,15 @@ namespace v8 { namespace internal {
* - esi : end of input (points to byte after last character in input). * - esi : end of input (points to byte after last character in input).
* - ebp : points to the location above the registers on the stack, * - ebp : points to the location above the registers on the stack,
* as if by the "enter <register_count>" opcode. * 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. * The registers eax, ebx and ecx are free to use for computations.
* *
* Each call to a public method should retain this convention. * Each call to a public method should retain this convention.
* The stack will have the following structure: * 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) * - at_start (if 1, start at start of string, if 0, don't)
* - int* capture_array (int[num_saved_registers_], for output). * - int* capture_array (int[num_saved_registers_], for output).
* - end of input (index of end of string, relative to *string_base) * - end of input (index of end of string, relative to *string_base)
...@@ -59,9 +63,9 @@ namespace v8 { namespace internal { ...@@ -59,9 +63,9 @@ namespace v8 { namespace internal {
* to *string_base) * to *string_base)
* - void** string_base (location of a handle containing the string) * - void** string_base (location of a handle containing the string)
* - return address * - return address
* - backup of esi * - backup of caller esi
* - backup of edi * - backup of caller edi
* - backup of ebx * - backup of caller ebx
* ebp-> - old ebp * ebp-> - old ebp
* - register 0 ebp[-4] (Only positions must be stored in the first * - register 0 ebp[-4] (Only positions must be stored in the first
* - register 1 ebp[-8] num_saved_registers_ registers) * - register 1 ebp[-8] num_saved_registers_ registers)
...@@ -77,7 +81,8 @@ namespace v8 { namespace internal { ...@@ -77,7 +81,8 @@ namespace v8 { namespace internal {
* int start_offset, * int start_offset,
* int end_offset, * int end_offset,
* int* capture_output_array, * int* capture_output_array,
* bool at_start) * bool at_start,
* byte* stack_area_top)
*/ */
#define __ masm_-> #define __ masm_->
...@@ -110,6 +115,12 @@ RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() { ...@@ -110,6 +115,12 @@ RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() {
backtrack_label_.Unuse(); backtrack_label_.Unuse();
exit_label_.Unuse(); exit_label_.Unuse();
check_preempt_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) { ...@@ -124,12 +135,18 @@ void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) {
void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) { void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) {
ASSERT(reg >= 0); ASSERT(reg >= 0);
ASSERT(reg < num_registers_); ASSERT(reg < num_registers_);
__ add(register_location(reg), Immediate(by)); if (by != 0) {
__ add(register_location(reg), Immediate(by));
}
} }
void RegExpMacroAssemblerIA32::Backtrack() { 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) { ...@@ -137,22 +154,11 @@ void RegExpMacroAssemblerIA32::Bind(Label* label) {
__ bind(label); __ bind(label);
} }
void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start, void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start,
Label* bitmap, Label* bitmap,
Label* on_zero) { Label* on_zero) {
UNIMPLEMENTED(); 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) { ...@@ -169,8 +175,10 @@ void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
void RegExpMacroAssemblerIA32::CheckNotAtStart(Label* on_not_at_start) { 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)); __ cmp(Operand(ebp, kAtStart), Immediate(0));
BranchOrBacktrack(equal, on_not_at_start); BranchOrBacktrack(equal, on_not_at_start);
// If we did, are we still at the start of the input?
__ mov(eax, Operand(ebp, kInputEndOffset)); __ mov(eax, Operand(ebp, kInputEndOffset));
__ add(eax, Operand(edi)); __ add(eax, Operand(edi));
__ cmp(eax, Operand(ebp, kInputStartOffset)); __ cmp(eax, Operand(ebp, kInputStartOffset));
...@@ -191,6 +199,7 @@ void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str, ...@@ -191,6 +199,7 @@ void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
int byte_length = str.length() * char_size(); int byte_length = str.length() * char_size();
int byte_offset = cp_offset * char_size(); int byte_offset = cp_offset * char_size();
if (check_end_of_string) { 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))); __ cmp(Operand(edi), Immediate(-(byte_offset + byte_length)));
BranchOrBacktrack(greater, on_failure); BranchOrBacktrack(greater, on_failure);
} }
...@@ -222,9 +231,9 @@ void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str, ...@@ -222,9 +231,9 @@ void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) { void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) {
Label fallthrough; Label fallthrough;
__ cmp(edi, Operand(esp, 0)); __ cmp(edi, Operand(backtrack_stackpointer(), 0));
__ j(not_equal, &fallthrough); __ j(not_equal, &fallthrough);
__ add(Operand(esp), Immediate(4)); // Pop. __ add(Operand(backtrack_stackpointer()), Immediate(kPointerSize)); // Pop.
BranchOrBacktrack(no_condition, on_equal); BranchOrBacktrack(no_condition, on_equal);
__ bind(&fallthrough); __ bind(&fallthrough);
} }
...@@ -234,20 +243,31 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase( ...@@ -234,20 +243,31 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
int start_reg, int start_reg,
Label* on_no_match) { Label* on_no_match) {
Label fallthrough; Label fallthrough;
__ mov(edx, register_location(start_reg)); __ mov(edx, register_location(start_reg)); // Index of start of capture
__ mov(ecx, register_location(start_reg + 1)); __ mov(ebx, register_location(start_reg + 1)); // Index of end of capture
__ sub(ecx, Operand(edx)); // Length to check. __ sub(ebx, Operand(edx)); // Length of capture.
BranchOrBacktrack(less, on_no_match);
// 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); __ j(equal, &fallthrough);
if (mode_ == ASCII) { if (mode_ == ASCII) {
Label success; Label success;
Label fail; Label fail;
Label loop_increment; Label loop_increment;
// Save register contents to make the registers available below.
__ push(edi); __ push(edi);
__ add(edx, Operand(esi)); __ push(backtrack_stackpointer());
__ add(edi, Operand(esi)); // After this, the eax, ebx, ecx, edx and edi registers are available.
__ add(ecx, Operand(edi));
__ 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; Label loop;
__ bind(&loop); __ bind(&loop);
...@@ -255,55 +275,71 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase( ...@@ -255,55 +275,71 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
__ cmpb_al(Operand(edx, 0)); __ cmpb_al(Operand(edx, 0));
__ j(equal, &loop_increment); __ j(equal, &loop_increment);
// Compare lower-case if letters. // Mismatch, try case-insensitive match (converting letters to lower-case).
__ or_(eax, 0x20); // To lower-case. __ or_(eax, 0x20); // Convert match character to lower-case.
__ lea(ebx, Operand(eax, -'a')); __ lea(ecx, Operand(eax, -'a'));
__ cmp(ebx, static_cast<int32_t>('z' - 'a')); __ cmp(ecx, static_cast<int32_t>('z' - 'a')); // Is eax a lowercase letter?
__ j(above, &fail); __ j(above, &fail);
__ movzx_b(ebx, Operand(edx, 0)); // Also convert capture character.
__ or_(ebx, 0x20); // To-lower-case __ movzx_b(ecx, Operand(edx, 0));
__ cmp(eax, Operand(ebx)); __ or_(ecx, 0x20);
__ cmp(eax, Operand(ecx));
__ j(not_equal, &fail); __ j(not_equal, &fail);
__ bind(&loop_increment); __ bind(&loop_increment);
// Increment pointers into match and capture strings.
__ add(Operand(edx), Immediate(1)); __ add(Operand(edx), Immediate(1));
__ add(Operand(edi), 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); __ j(below, &loop, taken);
__ jmp(&success); __ jmp(&success);
__ bind(&fail); __ bind(&fail);
// Restore original values before failing.
__ pop(backtrack_stackpointer());
__ pop(edi); __ pop(edi);
BranchOrBacktrack(no_condition, on_no_match); BranchOrBacktrack(no_condition, on_no_match);
__ bind(&success); __ 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)); __ sub(edi, Operand(esi));
} else { } else {
ASSERT(mode_ == UC16); ASSERT(mode_ == UC16);
// Save registers before calling C function.
__ push(esi); __ push(esi);
__ push(edi); __ push(edi);
__ push(ecx); __ push(backtrack_stackpointer());
__ push(ebx);
const int four_arguments = 4; const int four_arguments = 4;
FrameAlign(four_arguments); FrameAlign(four_arguments);
// Put arguments on stack. // Put arguments into allocated stack area.
__ mov(Operand(esp, 3 * kPointerSize), ecx); __ mov(Operand(esp, 3 * kPointerSize), ebx);
__ mov(ebx, Operand(ebp, kInputEndOffset)); __ mov(ecx, Operand(ebp, kInputEndOffset));
__ add(edi, Operand(ebx)); __ add(edi, Operand(ecx));
__ mov(Operand(esp, 2 * kPointerSize), edi); __ mov(Operand(esp, 2 * kPointerSize), edi);
__ add(eax, Operand(ebx)); __ add(eax, Operand(ecx));
__ mov(Operand(esp, 1 * kPointerSize), eax); __ mov(Operand(esp, 1 * kPointerSize), eax);
__ mov(eax, Operand(ebp, kInputBuffer)); __ mov(eax, Operand(ebp, kInputBuffer));
__ mov(Operand(esp, 0 * kPointerSize), eax); __ mov(Operand(esp, 0 * kPointerSize), eax);
Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16); Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16);
CallCFunction(function_address, four_arguments); CallCFunction(function_address, four_arguments);
__ pop(ecx); // Pop original values before reacting on result value.
__ pop(ebx);
__ pop(backtrack_stackpointer());
__ pop(edi); __ pop(edi);
__ pop(esi); __ pop(esi);
// Check if function returned non-zero for success or zero for failure.
__ or_(eax, Operand(eax)); __ or_(eax, Operand(eax));
BranchOrBacktrack(zero, on_no_match); BranchOrBacktrack(zero, on_no_match);
__ add(edi, Operand(ecx)); // On success, increment position by length of capture.
__ add(edi, Operand(ebx));
} }
__ bind(&fallthrough); __ bind(&fallthrough);
} }
...@@ -315,45 +351,60 @@ void RegExpMacroAssemblerIA32::CheckNotBackReference( ...@@ -315,45 +351,60 @@ void RegExpMacroAssemblerIA32::CheckNotBackReference(
Label fallthrough; Label fallthrough;
Label success; Label success;
Label fail; Label fail;
// Find length of back-referenced capture.
__ mov(edx, register_location(start_reg)); __ mov(edx, register_location(start_reg));
__ mov(ecx, register_location(start_reg + 1)); __ mov(eax, register_location(start_reg + 1));
__ sub(ecx, Operand(edx)); // Length to check. __ 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); BranchOrBacktrack(less, on_no_match);
// Succeed on empty capture (including no capture)
__ j(equal, &fallthrough); __ 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); __ mov(ebx, edi);
__ add(ebx, Operand(ecx)); __ add(ebx, Operand(eax));
BranchOrBacktrack(greater, on_no_match); BranchOrBacktrack(greater, on_no_match);
__ mov(ebx, edi); // Save register to make it available below.
__ add(edi, Operand(esi)); __ push(backtrack_stackpointer());
__ add(edx, Operand(esi));
__ add(ecx, Operand(edi)); // 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; Label loop;
__ bind(&loop); __ bind(&loop);
if (mode_ == ASCII) { if (mode_ == ASCII) {
__ movzx_b(eax, Operand(edx, 0)); __ movzx_b(eax, Operand(edx, 0));
__ cmpb_al(Operand(edi, 0)); __ cmpb_al(Operand(ebx, 0));
} else { } else {
ASSERT(mode_ == UC16); ASSERT(mode_ == UC16);
__ movzx_w(eax, Operand(edx, 0)); __ movzx_w(eax, Operand(edx, 0));
__ cmpw_ax(Operand(edi, 0)); __ cmpw_ax(Operand(ebx, 0));
} }
__ j(not_equal, &fail); __ j(not_equal, &fail);
// Increment pointers into capture and match string.
__ add(Operand(edx), Immediate(char_size())); __ add(Operand(edx), Immediate(char_size()));
__ add(Operand(edi), Immediate(char_size())); __ add(Operand(ebx), Immediate(char_size()));
__ cmp(edi, Operand(ecx)); // Check if we have reached end of match area.
__ cmp(ebx, Operand(ecx));
__ j(below, &loop); __ j(below, &loop);
__ jmp(&success); __ jmp(&success);
__ bind(&fail); __ bind(&fail);
__ mov(edi, ebx); // Restore backtrack stackpointer.
__ pop(backtrack_stackpointer());
BranchOrBacktrack(no_condition, on_no_match); BranchOrBacktrack(no_condition, on_no_match);
__ bind(&success); __ 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); __ bind(&fallthrough);
} }
...@@ -406,6 +457,7 @@ void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusAnd( ...@@ -406,6 +457,7 @@ void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusAnd(
BranchOrBacktrack(not_equal, on_not_equal); BranchOrBacktrack(not_equal, on_not_equal);
} }
bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type, bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
int cp_offset, int cp_offset,
bool check_offset, bool check_offset,
...@@ -428,7 +480,7 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type, ...@@ -428,7 +480,7 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
// Check range 0x09..0x0d // Check range 0x09..0x0d
__ sub(Operand(current_character()), Immediate('\t')); __ sub(Operand(current_character()), Immediate('\t'));
__ cmp(current_character(), '\r' - '\t'); __ cmp(current_character(), '\r' - '\t');
BranchOrBacktrack(above_equal, on_no_match); BranchOrBacktrack(above, on_no_match);
__ bind(&success); __ bind(&success);
return true; return true;
} }
...@@ -446,7 +498,7 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type, ...@@ -446,7 +498,7 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
BranchOrBacktrack(equal, on_no_match); BranchOrBacktrack(equal, on_no_match);
__ sub(Operand(current_character()), Immediate('\t')); __ sub(Operand(current_character()), Immediate('\t'));
__ cmp(current_character(), '\r' - '\t'); __ cmp(current_character(), '\r' - '\t');
BranchOrBacktrack(below, on_no_match); BranchOrBacktrack(below_equal, on_no_match);
return true; return true;
} }
return false; return false;
...@@ -459,7 +511,7 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type, ...@@ -459,7 +511,7 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
} }
__ sub(Operand(current_character()), Immediate('0')); __ sub(Operand(current_character()), Immediate('0'));
__ cmp(current_character(), '9' - '0'); __ cmp(current_character(), '9' - '0');
BranchOrBacktrack(greater_equal, on_no_match); BranchOrBacktrack(above, on_no_match);
return true; return true;
case 'D': case 'D':
// Match non ASCII-digits // Match non ASCII-digits
...@@ -470,7 +522,7 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type, ...@@ -470,7 +522,7 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
} }
__ sub(Operand(current_character()), Immediate('0')); __ sub(Operand(current_character()), Immediate('0'));
__ cmp(current_character(), '9' - '0'); __ cmp(current_character(), '9' - '0');
BranchOrBacktrack(below, on_no_match); BranchOrBacktrack(below_equal, on_no_match);
return true; return true;
case '.': { case '.': {
// Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029) // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
...@@ -479,18 +531,18 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type, ...@@ -479,18 +531,18 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
} else { } else {
LoadCurrentCharacterUnchecked(cp_offset, 1); LoadCurrentCharacterUnchecked(cp_offset, 1);
} }
// Compute hash value so exactly 0x0a and 0x0d become zero. __ xor_(Operand(current_character()), Immediate(0x01));
__ sub(Operand(current_character()), Immediate('\n')); // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
__ mov(eax, current_character()); __ sub(Operand(current_character()), Immediate(0x0b));
__ and_(current_character(), 0x01); __ cmp(current_character(), 0x0c - 0x0b);
__ shr(eax, 1); BranchOrBacktrack(below_equal, on_no_match);
__ xor_(current_character(), Operand(eax));
BranchOrBacktrack(equal, on_no_match);
if (mode_ == UC16) { if (mode_ == UC16) {
// Compare original value to 0x2028 and 0x2029, using the already // Compare original value to 0x2028 and 0x2029, using the already
// computed ((current_char - '\n') >> 1) in eax. // computed (current_char ^ 0x01 - 0x0b). I.e., check for
__ cmp(eax, (0x2028 - '\n') >> 1); // 0x201d (0x2028 - 0x0b) or 0x201e.
BranchOrBacktrack(equal, on_no_match); __ sub(Operand(current_character()), Immediate(0x2028 - 0x0b));
__ cmp(current_character(), 1);
BranchOrBacktrack(below_equal, on_no_match);
} }
return true; return true;
} }
...@@ -511,35 +563,6 @@ void RegExpMacroAssemblerIA32::DispatchHalfNibbleMap( ...@@ -511,35 +563,6 @@ void RegExpMacroAssemblerIA32::DispatchHalfNibbleMap(
Label* half_nibble_map, Label* half_nibble_map,
const Vector<Label*>& destinations) { const Vector<Label*>& destinations) {
UNIMPLEMENTED(); 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( ...@@ -548,17 +571,6 @@ void RegExpMacroAssemblerIA32::DispatchByteMap(
Label* byte_map, Label* byte_map,
const Vector<Label*>& destinations) { const Vector<Label*>& destinations) {
UNIMPLEMENTED(); 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( ...@@ -567,16 +579,6 @@ void RegExpMacroAssemblerIA32::DispatchHighByteMap(
Label* byte_map, Label* byte_map,
const Vector<Label*>& destinations) { const Vector<Label*>& destinations) {
UNIMPLEMENTED(); 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) { ...@@ -586,6 +588,7 @@ void RegExpMacroAssemblerIA32::EmitOrLink(Label* label) {
void RegExpMacroAssemblerIA32::Fail() { void RegExpMacroAssemblerIA32::Fail() {
ASSERT(FAILURE == 0); // Return value for failure is zero.
__ xor_(eax, Operand(eax)); // zero eax. __ xor_(eax, Operand(eax)); // zero eax.
__ jmp(&exit_label_); __ jmp(&exit_label_);
} }
...@@ -602,6 +605,46 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) { ...@@ -602,6 +605,46 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
__ push(esi); __ push(esi);
__ push(edi); __ push(edi);
__ push(ebx); // Callee-save on MacOS. __ 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)); __ enter(Immediate(num_registers_ * kPointerSize));
// Load string length. // Load string length.
__ mov(esi, Operand(ebp, kInputEndOffset)); __ mov(esi, Operand(ebp, kInputEndOffset));
...@@ -617,15 +660,32 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) { ...@@ -617,15 +660,32 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
__ add(esi, Operand(edx)); __ add(esi, Operand(edx));
if (num_saved_registers_ > 0) { if (num_saved_registers_ > 0) {
// Fill saved registers with initial value = start offset - 1 // Fill saved registers with initial value = start offset - 1
__ mov(ecx, -num_saved_registers_); // Fill in stack push order, to avoid accessing across an unwritten
__ mov(eax, Operand(edi)); // page (a problem on Windows).
__ sub(Operand(eax), Immediate(char_size())); 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; Label init_loop;
__ bind(&init_loop); __ bind(&init_loop);
__ mov(Operand(ebp, ecx, times_4, +0), eax); __ mov(Operand(ebp, ecx, times_4, +0), eax);
__ inc(ecx); __ sub(Operand(ecx), Immediate(1));
__ j(not_equal, &init_loop); __ 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. // Load previous char as initial value of current-character.
Label at_start; Label at_start;
__ cmp(Operand(ebp, kAtStart), Immediate(0)); __ cmp(Operand(ebp, kAtStart), Immediate(0));
...@@ -655,11 +715,12 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) { ...@@ -655,11 +715,12 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
__ mov(Operand(ebx, i * kPointerSize), eax); __ mov(Operand(ebx, i * kPointerSize), eax);
} }
} }
__ mov(eax, Immediate(1)); __ mov(eax, Immediate(SUCCESS));
} }
// Exit and return eax // Exit and return eax
__ bind(&exit_label_); __ bind(&exit_label_);
__ leave(); __ leave();
__ bind(&exit_without_leave); // For exiting before doing enter.
__ pop(ebx); __ pop(ebx);
__ pop(edi); __ pop(edi);
__ pop(esi); __ pop(esi);
...@@ -671,16 +732,16 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) { ...@@ -671,16 +732,16 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
Backtrack(); Backtrack();
} }
Label exit_with_exception;
// Preempt-code // Preempt-code
if (check_preempt_label_.is_linked()) { if (check_preempt_label_.is_linked()) {
__ bind(&check_preempt_label_); __ 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). __ push(backtrack_stackpointer());
// Then dispatch to an action depending on state, and loop.
__ push(edi); __ push(edi);
Label retry; Label retry;
Label stack_overflow;
__ bind(&retry); __ bind(&retry);
int num_arguments = 2; int num_arguments = 2;
...@@ -689,26 +750,57 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) { ...@@ -689,26 +750,57 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
__ lea(eax, Operand(esp, -kPointerSize)); __ lea(eax, Operand(esp, -kPointerSize));
__ mov(Operand(esp, 0 * kPointerSize), eax); __ mov(Operand(esp, 0 * kPointerSize), eax);
CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments); 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 stack_guard_limit =
ExternalReference::address_of_stack_guard_limit(); ExternalReference::address_of_stack_guard_limit();
// Check if we are still preempted.
__ or_(eax, Operand(eax));
__ j(not_equal, &stack_overflow);
__ cmp(esp, Operand::StaticVariable(stack_guard_limit)); __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
__ j(below_equal, &retry); __ j(below_equal, &retry);
__ pop(edi); __ pop(edi);
__ pop(backtrack_stackpointer());
// String might have moved: Recompute esi from scratch. // String might have moved: Recompute esi from scratch.
__ mov(esi, Operand(esp, kInputBuffer)); __ mov(esi, Operand(ebp, kInputBuffer));
__ mov(esi, Operand(esi, 0)); __ 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(); SafeReturn();
}
__ bind(&stack_overflow); if (exit_with_exception.is_linked()) {
// Exit with result -1 to signal thrown exception. // If any of the code above needed to exit with an exception.
__ mov(eax, -1); __ bind(&exit_with_exception);
// Exit with Result EXCEPTION(-1) to signal thrown exception.
__ mov(eax, EXCEPTION);
__ jmp(&exit_label_); __ jmp(&exit_label_);
} }
...@@ -769,28 +861,32 @@ void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset, ...@@ -769,28 +861,32 @@ void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
void RegExpMacroAssemblerIA32::PopCurrentPosition() { void RegExpMacroAssemblerIA32::PopCurrentPosition() {
__ pop(edi); Pop(edi);
} }
void RegExpMacroAssemblerIA32::PopRegister(int register_index) { void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
__ pop(register_location(register_index)); Pop(eax);
__ mov(register_location(register_index), eax);
} }
void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) { void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) {
__ push(Immediate::CodeRelativeOffset(label)); Push(Immediate::CodeRelativeOffset(label));
CheckStackLimit(); CheckStackLimit();
} }
void RegExpMacroAssemblerIA32::PushCurrentPosition() { void RegExpMacroAssemblerIA32::PushCurrentPosition() {
__ push(edi); Push(edi);
} }
void RegExpMacroAssemblerIA32::PushRegister(int register_index) { void RegExpMacroAssemblerIA32::PushRegister(int register_index,
__ push(register_location(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) { ...@@ -800,7 +896,7 @@ void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) {
void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(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, ...@@ -827,7 +923,7 @@ void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg,
void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(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) { ...@@ -837,6 +933,38 @@ void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
static unibrow::Mapping<unibrow::Ecma262Canonicalize> canonicalize; 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 RegExpMacroAssemblerIA32::CaseInsensitiveCompareUC16(uc16** buffer,
int byte_offset1, int byte_offset1,
int byte_offset2, int byte_offset2,
...@@ -879,11 +1007,10 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address return_address, ...@@ -879,11 +1007,10 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address return_address,
// Prepare for possible GC. // Prepare for possible GC.
Handle<Code> code_handle(re_code); Handle<Code> code_handle(re_code);
#ifdef DEBUG
CHECK(re_code->instruction_start() <= return_address); ASSERT(re_code->instruction_start() <= return_address);
CHECK(return_address <= ASSERT(return_address <=
re_code->instruction_start() + re_code->instruction_size()); re_code->instruction_start() + re_code->instruction_size());
#endif
Object* result = Execution::HandleStackGuardInterrupt(); Object* result = Execution::HandleStackGuardInterrupt();
...@@ -899,6 +1026,17 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address return_address, ...@@ -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) { Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
ASSERT(register_index < (1<<30)); ASSERT(register_index < (1<<30));
if (num_registers_ <= register_index) { if (num_registers_ <= register_index) {
...@@ -908,16 +1046,6 @@ Operand RegExpMacroAssemblerIA32::register_location(int 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, void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset,
Label* on_outside_input) { Label* on_outside_input) {
__ cmp(edi, -cp_offset * char_size()); __ cmp(edi, -cp_offset * char_size());
...@@ -926,7 +1054,8 @@ void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset, ...@@ -926,7 +1054,8 @@ void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset,
void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition, void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
Label* to) { Label* to,
Hint hint) {
if (condition < 0) { // No condition if (condition < 0) { // No condition
if (to == NULL) { if (to == NULL) {
Backtrack(); Backtrack();
...@@ -936,10 +1065,10 @@ void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition, ...@@ -936,10 +1065,10 @@ void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
return; return;
} }
if (to == NULL) { if (to == NULL) {
__ j(condition, &backtrack_label_); __ j(condition, &backtrack_label_, hint);
return; return;
} }
__ j(condition, to); __ j(condition, to, hint);
} }
...@@ -952,25 +1081,60 @@ void RegExpMacroAssemblerIA32::SafeCall(Label* to) { ...@@ -952,25 +1081,60 @@ void RegExpMacroAssemblerIA32::SafeCall(Label* to) {
void RegExpMacroAssemblerIA32::SafeReturn() { void RegExpMacroAssemblerIA32::SafeReturn() {
__ pop(ecx); __ pop(ebx);
__ add(Operand(ecx), Immediate(self_)); __ add(Operand(ebx), Immediate(self_));
__ jmp(Operand(ecx)); __ 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() { void RegExpMacroAssemblerIA32::CheckStackLimit() {
if (FLAG_check_stack) { if (FLAG_check_stack) {
// Check for preemption first. Label no_stack_overflow;
Label no_preempt; ExternalReference stack_limit =
// Check for preemption. ExternalReference::address_of_regexp_stack_limit();
ExternalReference stack_guard_limit = __ cmp(backtrack_stackpointer(), Operand::StaticVariable(stack_limit));
ExternalReference::address_of_stack_guard_limit(); __ j(above, &no_stack_overflow);
__ cmp(esp, Operand::StaticVariable(stack_guard_limit));
__ j(above, &no_preempt, taken);
SafeCall(&check_preempt_label_); SafeCall(&stack_overflow_label_);
__ bind(&no_preempt); __ bind(&no_stack_overflow);
} }
} }
......
...@@ -38,6 +38,7 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler { ...@@ -38,6 +38,7 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
RegExpMacroAssemblerIA32(Mode mode, int registers_to_save); RegExpMacroAssemblerIA32(Mode mode, int registers_to_save);
virtual ~RegExpMacroAssemblerIA32(); virtual ~RegExpMacroAssemblerIA32();
virtual int stack_limit_slack();
virtual void AdvanceCurrentPosition(int by); virtual void AdvanceCurrentPosition(int by);
virtual void AdvanceRegister(int reg, int by); virtual void AdvanceRegister(int reg, int by);
virtual void Backtrack(); virtual void Backtrack();
...@@ -53,6 +54,8 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler { ...@@ -53,6 +54,8 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
int cp_offset, int cp_offset,
Label* on_failure, Label* on_failure,
bool check_end_of_string); 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 CheckGreedyLoop(Label* on_tos_equals_current_position);
virtual void CheckNotAtStart(Label* on_not_at_start); virtual void CheckNotAtStart(Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, Label* on_no_match); virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
...@@ -96,7 +99,8 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler { ...@@ -96,7 +99,8 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
virtual void PopRegister(int register_index); virtual void PopRegister(int register_index);
virtual void PushBacktrack(Label* label); virtual void PushBacktrack(Label* label);
virtual void PushCurrentPosition(); 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 ReadCurrentPositionFromRegister(int reg);
virtual void ReadStackPointerFromRegister(int reg); virtual void ReadStackPointerFromRegister(int reg);
virtual void SetRegister(int register_index, int to); virtual void SetRegister(int register_index, int to);
...@@ -104,26 +108,15 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler { ...@@ -104,26 +108,15 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
virtual void WriteStackPointerToRegister(int reg); virtual void WriteStackPointerToRegister(int reg);
template <typename T> static Result Execute(Code* code,
static inline Result Execute(Code* code, Address* input,
T** input, int start_offset,
int start_offset, int end_offset,
int end_offset, int* output,
int* output, bool at_start);
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);
}
private: 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_ebx = sizeof(uint32_t);
static const int kBackup_edi = 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); static const int kBackup_esi = kBackup_edi + sizeof(uint32_t);
...@@ -133,24 +126,30 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler { ...@@ -133,24 +126,30 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
static const int kInputEndOffset = kInputStartOffset + sizeof(uint32_t); static const int kInputEndOffset = kInputStartOffset + sizeof(uint32_t);
static const int kRegisterOutput = kInputEndOffset + sizeof(uint32_t); static const int kRegisterOutput = kInputEndOffset + sizeof(uint32_t);
static const int kAtStart = kRegisterOutput + sizeof(uint32_t); static const int kAtStart = kRegisterOutput + sizeof(uint32_t);
static const int kStackHighEnd = kAtStart + sizeof(uint32_t);
// Initial size of code buffer. // Initial size of code buffer.
static const size_t kRegExpCodeSize = 1024; static const size_t kRegExpCodeSize = 1024;
// Initial size of constant buffers allocated during compilation. // Initial size of constant buffers allocated during compilation.
static const int kRegExpConstantsSize = 256; 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; static const int kMaxInlineStringTests = 32;
// Compares two-byte strings case insensitively. // Compares two-byte strings case insensitively.
// Called from generated RegExp code.
static int CaseInsensitiveCompareUC16(uc16** buffer, static int CaseInsensitiveCompareUC16(uc16** buffer,
int byte_offset1, int byte_offset1,
int byte_offset2, int byte_offset2,
size_t byte_length); 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 // Check whether preemption has been requested.
// (and checks if we have hit the stack limit too). void CheckPreemption();
// Check whether we are exceeding the stack limit on the backtrack stack.
void CheckStackLimit(); void CheckStackLimit();
// Called from RegExp if the stack-guard is triggered. // Called from RegExp if the stack-guard is triggered.
...@@ -158,6 +157,12 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler { ...@@ -158,6 +157,12 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
// returning. // returning.
static int CheckStackGuardState(Address return_address, Code* re_code); 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 // Checks whether the given offset from the current position is before
// the end of the string. // the end of the string.
void CheckPosition(int cp_offset, Label* on_outside_input); void CheckPosition(int cp_offset, Label* on_outside_input);
...@@ -166,14 +171,18 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler { ...@@ -166,14 +171,18 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
Operand register_location(int register_index); Operand register_location(int register_index);
// The register containing the current character after LoadCurrentCharacter. // 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) // 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 // Equivalent to a conditional branch to the label, unless the label
// is NULL, in which case it is a conditional Backtrack. // 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) // Load the address of a "constant buffer" (a slice of a byte array)
// into a register. The address is computed from the ByteArray* address // into a register. The address is computed from the ByteArray* address
...@@ -182,30 +191,50 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler { ...@@ -182,30 +191,50 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
// Call and return internally in the generated code in a way that // 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) // is GC-safe (i.e., doesn't leave absolute code addresses on the stack)
void SafeCall(Label* to); inline void SafeCall(Label* to);
void SafeReturn(); 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. // 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], // 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. // 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 // Calls a C function and cleans up the space for arguments allocated
// by FrameAlign. The called function is not allowed to trigger a garbage // by FrameAlign. The called function is not allowed to trigger a garbage
// collection, since that might move the code and invalidate the return // collection, since that might move the code and invalidate the return
// address // address (unless this is somehow accounted for).
void CallCFunction(Address function_address, int num_arguments); inline void CallCFunction(Address function_address, int num_arguments);
MacroAssembler* masm_; MacroAssembler* masm_;
// Constant buffer provider. Allocates external storage for storing // Constant buffer provider. Allocates external storage for storing
// constants. // constants.
ByteArrayProvider constants_; ByteArrayProvider constants_;
// Which mode to generate code for (ASCII or UTF16). // Which mode to generate code for (ASCII or UTF16).
Mode mode_; Mode mode_;
// One greater than maximal register index actually used. // One greater than maximal register index actually used.
int num_registers_; int num_registers_;
// Number of registers to output at the end (the saved registers // Number of registers to output at the end (the saved registers
// are always 0..num_saved_registers_-1) // are always 0..num_saved_registers_-1)
int num_saved_registers_; int num_saved_registers_;
// Labels used internally. // Labels used internally.
Label entry_label_; Label entry_label_;
Label start_label_; Label start_label_;
...@@ -213,6 +242,8 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler { ...@@ -213,6 +242,8 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
Label backtrack_label_; Label backtrack_label_;
Label exit_label_; Label exit_label_;
Label check_preempt_label_; Label check_preempt_label_;
Label stack_overflow_label_;
// Handle used to represent the generated code object itself. // Handle used to represent the generated code object itself.
Handle<Object> self_; Handle<Object> self_;
}; };
......
...@@ -89,7 +89,9 @@ void RegExpMacroAssemblerIrregexp::PopRegister(int register_index) { ...@@ -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); ASSERT(register_index >= 0);
Emit(BC_PUSH_REGISTER); Emit(BC_PUSH_REGISTER);
Emit(register_index); Emit(register_index);
......
...@@ -48,6 +48,8 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler { ...@@ -48,6 +48,8 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
// upon destruction of the assembler. // upon destruction of the assembler.
explicit RegExpMacroAssemblerIrregexp(Vector<byte>); explicit RegExpMacroAssemblerIrregexp(Vector<byte>);
virtual ~RegExpMacroAssemblerIrregexp(); 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 Bind(Label* label);
virtual void EmitOrLink(Label* label); virtual void EmitOrLink(Label* label);
virtual void AdvanceCurrentPosition(int by); // Signed cp change. virtual void AdvanceCurrentPosition(int by); // Signed cp change.
...@@ -59,7 +61,8 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler { ...@@ -59,7 +61,8 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
virtual void Succeed(); virtual void Succeed();
virtual void Fail(); virtual void Fail();
virtual void PopRegister(int register_index); 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 AdvanceRegister(int reg, int by); // r[reg] += by.
virtual void SetRegister(int register_index, int to); virtual void SetRegister(int register_index, int to);
virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
......
...@@ -95,7 +95,8 @@ void RegExpMacroAssemblerTracer::GoTo(Label* label) { ...@@ -95,7 +95,8 @@ void RegExpMacroAssemblerTracer::GoTo(Label* label) {
void RegExpMacroAssemblerTracer::PushBacktrack(Label* label) { void RegExpMacroAssemblerTracer::PushBacktrack(Label* label) {
PrintF(" PushBacktrack(label[%08x]);\n", label); PrintF(" PushBacktrack(label[%08x]);\n",
label);
assembler_->PushBacktrack(label); assembler_->PushBacktrack(label);
} }
...@@ -118,9 +119,13 @@ void RegExpMacroAssemblerTracer::PopRegister(int register_index) { ...@@ -118,9 +119,13 @@ void RegExpMacroAssemblerTracer::PopRegister(int register_index) {
} }
void RegExpMacroAssemblerTracer::PushRegister(int register_index) { void RegExpMacroAssemblerTracer::PushRegister(
PrintF(" PushRegister(register=%d);\n", register_index); int register_index,
assembler_->PushRegister(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);
} }
......
...@@ -35,6 +35,7 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler { ...@@ -35,6 +35,7 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
public: public:
explicit RegExpMacroAssemblerTracer(RegExpMacroAssembler* assembler); explicit RegExpMacroAssemblerTracer(RegExpMacroAssembler* assembler);
virtual ~RegExpMacroAssemblerTracer(); virtual ~RegExpMacroAssemblerTracer();
virtual int stack_limit_slack() { return assembler_->stack_limit_slack(); }
virtual void AdvanceCurrentPosition(int by); // Signed cp change. virtual void AdvanceCurrentPosition(int by); // Signed cp change.
virtual void AdvanceRegister(int reg, int by); // r[reg] += by. virtual void AdvanceRegister(int reg, int by); // r[reg] += by.
...@@ -98,7 +99,8 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler { ...@@ -98,7 +99,8 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
virtual void PopRegister(int register_index); virtual void PopRegister(int register_index);
virtual void PushBacktrack(Label* label); virtual void PushBacktrack(Label* label);
virtual void PushCurrentPosition(); 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 ReadCurrentPositionFromRegister(int reg);
virtual void ReadStackPointerFromRegister(int reg); virtual void ReadStackPointerFromRegister(int reg);
virtual void SetRegister(int register_index, int to); virtual void SetRegister(int register_index, int to);
......
...@@ -68,10 +68,11 @@ ArraySlice ByteArrayProvider::GetBuffer(unsigned int size, ...@@ -68,10 +68,11 @@ ArraySlice ByteArrayProvider::GetBuffer(unsigned int size,
return ArraySlice(current_byte_array_, free_offset); return ArraySlice(current_byte_array_, free_offset);
} }
template <typename T> template <typename T>
ArraySlice ByteArrayProvider::GetBuffer(Vector<T> values) { ArraySlice ByteArrayProvider::GetBuffer(Vector<T> values) {
ArraySlice slice = GetBuffer(values.length(), sizeof(T)); ArraySlice slice = GetBuffer(values.length(), sizeof(T));
memcpy(slice.location(), values.start(), values.length() * sizeof(T)); memcpy(slice.location(), values.start(), values.length() * sizeof(T));
return slice; return slice;
} }
} } } } // namespace v8::internal
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
namespace v8 { namespace internal { namespace v8 { namespace internal {
struct DisjunctDecisionRow { struct DisjunctDecisionRow {
RegExpCharacterClass cc; RegExpCharacterClass cc;
Label* on_match; Label* on_match;
...@@ -42,12 +41,24 @@ class RegExpMacroAssembler { ...@@ -42,12 +41,24 @@ class RegExpMacroAssembler {
enum IrregexpImplementation { enum IrregexpImplementation {
kIA32Implementation, kIA32Implementation,
kARMImplementation, kARMImplementation,
kBytecodeImplementation}; kBytecodeImplementation
};
enum StackCheckFlag {
kNoStackLimitCheck = false,
kCheckStackLimit = true
};
RegExpMacroAssembler(); RegExpMacroAssembler();
virtual ~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 AdvanceCurrentPosition(int by) = 0; // Signed cp change.
virtual void AdvanceRegister(int reg, int by) = 0; // r[reg] += by. 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 Backtrack() = 0;
virtual void Bind(Label* label) = 0; virtual void Bind(Label* label) = 0;
// Check the current character against a bitmap. The range of the current // Check the current character against a bitmap. The range of the current
...@@ -145,9 +156,12 @@ class RegExpMacroAssembler { ...@@ -145,9 +156,12 @@ class RegExpMacroAssembler {
int characters = 1) = 0; int characters = 1) = 0;
virtual void PopCurrentPosition() = 0; virtual void PopCurrentPosition() = 0;
virtual void PopRegister(int register_index) = 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 PushBacktrack(Label* label) = 0;
virtual void PushCurrentPosition() = 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 ReadCurrentPositionFromRegister(int reg) = 0;
virtual void ReadStackPointerFromRegister(int reg) = 0; virtual void ReadStackPointerFromRegister(int reg) = 0;
virtual void SetRegister(int register_index, int to) = 0; virtual void SetRegister(int register_index, int to) = 0;
......
// 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
// 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_ */
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "debug.h" #include "debug.h"
#include "execution.h" #include "execution.h"
#include "v8threads.h" #include "v8threads.h"
#include "regexp-stack.h"
namespace v8 { namespace v8 {
...@@ -125,6 +126,7 @@ bool ThreadManager::RestoreThread() { ...@@ -125,6 +126,7 @@ bool ThreadManager::RestoreThread() {
from = Top::RestoreThread(from); from = Top::RestoreThread(from);
from = Debug::RestoreDebug(from); from = Debug::RestoreDebug(from);
from = StackGuard::RestoreStackGuard(from); from = StackGuard::RestoreStackGuard(from);
from = RegExpStack::RestoreStack(from);
Thread::SetThreadLocal(thread_state_key, NULL); Thread::SetThreadLocal(thread_state_key, NULL);
state->Unlink(); state->Unlink();
state->LinkInto(ThreadState::FREE_LIST); state->LinkInto(ThreadState::FREE_LIST);
...@@ -149,7 +151,8 @@ static int ArchiveSpacePerThread() { ...@@ -149,7 +151,8 @@ static int ArchiveSpacePerThread() {
return HandleScopeImplementer::ArchiveSpacePerThread() + return HandleScopeImplementer::ArchiveSpacePerThread() +
Top::ArchiveSpacePerThread() + Top::ArchiveSpacePerThread() +
Debug::ArchiveSpacePerThread() + Debug::ArchiveSpacePerThread() +
StackGuard::ArchiveSpacePerThread(); StackGuard::ArchiveSpacePerThread() +
RegExpStack::ArchiveSpacePerThread();
} }
...@@ -230,6 +233,7 @@ void ThreadManager::EagerlyArchiveThread() { ...@@ -230,6 +233,7 @@ void ThreadManager::EagerlyArchiveThread() {
to = Top::ArchiveThread(to); to = Top::ArchiveThread(to);
to = Debug::ArchiveDebug(to); to = Debug::ArchiveDebug(to);
to = StackGuard::ArchiveStackGuard(to); to = StackGuard::ArchiveStackGuard(to);
to = RegExpStack::ArchiveStack(to);
lazily_archived_thread_.Initialize(ThreadHandle::INVALID); lazily_archived_thread_.Initialize(ThreadHandle::INVALID);
lazily_archived_thread_state_ = NULL; lazily_archived_thread_state_ = NULL;
} }
......
...@@ -598,7 +598,7 @@ TEST(MacroAssembler) { ...@@ -598,7 +598,7 @@ TEST(MacroAssembler) {
foo_chars[2] = 'o'; foo_chars[2] = 'o';
Vector<const uc16> foo(foo_chars, 3); Vector<const uc16> foo(foo_chars, 3);
m.SetRegister(4, 42); m.SetRegister(4, 42);
m.PushRegister(4); m.PushRegister(4, RegExpMacroAssembler::kNoStackLimitCheck);
m.AdvanceRegister(4, 42); m.AdvanceRegister(4, 42);
m.GoTo(&start); m.GoTo(&start);
m.Fail(); m.Fail();
...@@ -666,6 +666,40 @@ class ContextInitializer { ...@@ -666,6 +666,40 @@ class ContextInitializer {
v8::internal::StackGuard stack_guard_; 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) { TEST(MacroAssemblerIA32Success) {
v8::V8::Initialize(); v8::V8::Initialize();
...@@ -687,12 +721,12 @@ TEST(MacroAssemblerIA32Success) { ...@@ -687,12 +721,12 @@ TEST(MacroAssemblerIA32Success) {
int end_offset = start_offset + seq_input->length(); int end_offset = start_offset + seq_input->length();
RegExpMacroAssemblerIA32::Result result = RegExpMacroAssemblerIA32::Result result =
RegExpMacroAssemblerIA32::Execute(*code, ExecuteIA32(*code,
seq_input.location(), seq_input.location(),
start_offset, start_offset,
end_offset, end_offset,
captures, captures,
true); true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result); CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(-1, captures[0]); CHECK_EQ(-1, captures[0]);
...@@ -732,12 +766,12 @@ TEST(MacroAssemblerIA32Simple) { ...@@ -732,12 +766,12 @@ TEST(MacroAssemblerIA32Simple) {
int end_offset = start_offset + seq_input->length(); int end_offset = start_offset + seq_input->length();
RegExpMacroAssemblerIA32::Result result = RegExpMacroAssemblerIA32::Result result =
RegExpMacroAssemblerIA32::Execute(*code, ExecuteIA32(*code,
seq_input.location(), seq_input.location(),
start_offset, start_offset,
end_offset, end_offset,
captures, captures,
true); true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result); CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(0, captures[0]); CHECK_EQ(0, captures[0]);
...@@ -751,12 +785,12 @@ TEST(MacroAssemblerIA32Simple) { ...@@ -751,12 +785,12 @@ TEST(MacroAssemblerIA32Simple) {
start_offset = start_adr - reinterpret_cast<Address>(*seq_input); start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
end_offset = start_offset + seq_input->length(); end_offset = start_offset + seq_input->length();
result = RegExpMacroAssemblerIA32::Execute(*code, result = ExecuteIA32(*code,
seq_input.location(), seq_input.location(),
start_offset, start_offset,
end_offset, end_offset,
captures, captures,
true); true);
CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result); CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result);
} }
...@@ -794,12 +828,12 @@ TEST(MacroAssemblerIA32SimpleUC16) { ...@@ -794,12 +828,12 @@ TEST(MacroAssemblerIA32SimpleUC16) {
int end_offset = start_offset + seq_input->length() * sizeof(uc16); int end_offset = start_offset + seq_input->length() * sizeof(uc16);
RegExpMacroAssemblerIA32::Result result = RegExpMacroAssemblerIA32::Result result =
RegExpMacroAssemblerIA32::Execute(*code, ExecuteIA32(*code,
seq_input.location(), seq_input.location(),
start_offset, start_offset,
end_offset, end_offset,
captures, captures,
true); true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result); CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(0, captures[0]); CHECK_EQ(0, captures[0]);
...@@ -814,12 +848,12 @@ TEST(MacroAssemblerIA32SimpleUC16) { ...@@ -814,12 +848,12 @@ TEST(MacroAssemblerIA32SimpleUC16) {
start_offset = start_adr - reinterpret_cast<Address>(*seq_input); start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
end_offset = start_offset + seq_input->length() * sizeof(uc16); end_offset = start_offset + seq_input->length() * sizeof(uc16);
result = RegExpMacroAssemblerIA32::Execute(*code, result = ExecuteIA32(*code,
seq_input.location(), seq_input.location(),
start_offset, start_offset,
end_offset, end_offset,
captures, captures,
true); true);
CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result); CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result);
} }
...@@ -853,12 +887,12 @@ TEST(MacroAssemblerIA32Backtrack) { ...@@ -853,12 +887,12 @@ TEST(MacroAssemblerIA32Backtrack) {
int end_offset = start_offset + seq_input->length(); int end_offset = start_offset + seq_input->length();
RegExpMacroAssemblerIA32::Result result = RegExpMacroAssemblerIA32::Result result =
RegExpMacroAssemblerIA32::Execute(*code, ExecuteIA32(*code,
seq_input.location(), seq_input.location(),
start_offset, start_offset,
end_offset, end_offset,
NULL, NULL,
true); true);
CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result); CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result);
} }
...@@ -897,12 +931,12 @@ TEST(MacroAssemblerIA32BackReferenceASCII) { ...@@ -897,12 +931,12 @@ TEST(MacroAssemblerIA32BackReferenceASCII) {
int output[3]; int output[3];
RegExpMacroAssemblerIA32::Result result = RegExpMacroAssemblerIA32::Result result =
RegExpMacroAssemblerIA32::Execute(*code, ExecuteIA32(*code,
seq_input.location(), seq_input.location(),
start_offset, start_offset,
end_offset, end_offset,
output, output,
true); true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result); CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(0, output[0]); CHECK_EQ(0, output[0]);
...@@ -947,12 +981,12 @@ TEST(MacroAssemblerIA32BackReferenceUC16) { ...@@ -947,12 +981,12 @@ TEST(MacroAssemblerIA32BackReferenceUC16) {
int output[3]; int output[3];
RegExpMacroAssemblerIA32::Result result = RegExpMacroAssemblerIA32::Result result =
RegExpMacroAssemblerIA32::Execute(*code, ExecuteIA32(*code,
seq_input.location(), seq_input.location(),
start_offset, start_offset,
end_offset, end_offset,
output, output,
true); true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result); CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(0, output[0]); CHECK_EQ(0, output[0]);
...@@ -1000,22 +1034,22 @@ TEST(MacroAssemblerIA32AtStart) { ...@@ -1000,22 +1034,22 @@ TEST(MacroAssemblerIA32AtStart) {
int end_offset = start_offset + seq_input->length(); int end_offset = start_offset + seq_input->length();
RegExpMacroAssemblerIA32::Result result = RegExpMacroAssemblerIA32::Result result =
RegExpMacroAssemblerIA32::Execute(*code, ExecuteIA32(*code,
seq_input.location(), seq_input.location(),
start_offset, start_offset,
end_offset, end_offset,
NULL, NULL,
true); true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result); CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
start_offset += 3; start_offset += 3;
result = RegExpMacroAssemblerIA32::Execute(*code, result = ExecuteIA32(*code,
seq_input.location(), seq_input.location(),
start_offset, start_offset,
end_offset, end_offset,
NULL, NULL,
false); false);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result); CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
} }
...@@ -1065,12 +1099,12 @@ TEST(MacroAssemblerIA32BackRefNoCase) { ...@@ -1065,12 +1099,12 @@ TEST(MacroAssemblerIA32BackRefNoCase) {
int output[4]; int output[4];
RegExpMacroAssemblerIA32::Result result = RegExpMacroAssemblerIA32::Result result =
RegExpMacroAssemblerIA32::Execute(*code, ExecuteIA32(*code,
seq_input.location(), seq_input.location(),
start_offset, start_offset,
end_offset, end_offset,
output, output,
true); true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result); CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(0, output[0]); CHECK_EQ(0, output[0]);
...@@ -1094,13 +1128,13 @@ TEST(MacroAssemblerIA32Registers) { ...@@ -1094,13 +1128,13 @@ TEST(MacroAssemblerIA32Registers) {
Label fail; Label fail;
Label backtrack; Label backtrack;
m.WriteCurrentPositionToRegister(out1, 0); // Output: [0] m.WriteCurrentPositionToRegister(out1, 0); // Output: [0]
m.PushRegister(out1); m.PushRegister(out1, RegExpMacroAssembler::kNoStackLimitCheck);
m.PushBacktrack(&backtrack); m.PushBacktrack(&backtrack);
m.WriteStackPointerToRegister(sp); m.WriteStackPointerToRegister(sp);
// Fill stack and registers // Fill stack and registers
m.AdvanceCurrentPosition(2); m.AdvanceCurrentPosition(2);
m.WriteCurrentPositionToRegister(out1, 0); m.WriteCurrentPositionToRegister(out1, 0);
m.PushRegister(out1); m.PushRegister(out1, RegExpMacroAssembler::kNoStackLimitCheck);
m.PushBacktrack(&fail); m.PushBacktrack(&fail);
// Drop backtrack stack frames. // Drop backtrack stack frames.
m.ReadStackPointerFromRegister(sp); m.ReadStackPointerFromRegister(sp);
...@@ -1135,8 +1169,8 @@ TEST(MacroAssemblerIA32Registers) { ...@@ -1135,8 +1169,8 @@ TEST(MacroAssemblerIA32Registers) {
Label loop3; Label loop3;
Label exit_loop3; Label exit_loop3;
m.PushRegister(out4); m.PushRegister(out4, RegExpMacroAssembler::kNoStackLimitCheck);
m.PushRegister(out4); m.PushRegister(out4, RegExpMacroAssembler::kNoStackLimitCheck);
m.ReadCurrentPositionFromRegister(out3); m.ReadCurrentPositionFromRegister(out3);
m.Bind(&loop3); m.Bind(&loop3);
m.AdvanceCurrentPosition(1); m.AdvanceCurrentPosition(1);
...@@ -1166,12 +1200,12 @@ TEST(MacroAssemblerIA32Registers) { ...@@ -1166,12 +1200,12 @@ TEST(MacroAssemblerIA32Registers) {
int output[5]; int output[5];
RegExpMacroAssemblerIA32::Result result = RegExpMacroAssemblerIA32::Result result =
RegExpMacroAssemblerIA32::Execute(*code, ExecuteIA32(*code,
seq_input.location(), seq_input.location(),
start_offset, start_offset,
end_offset, end_offset,
output, output,
true); true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result); CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(0, output[0]); CHECK_EQ(0, output[0]);
...@@ -1207,12 +1241,12 @@ TEST(MacroAssemblerIA32StackOverflow) { ...@@ -1207,12 +1241,12 @@ TEST(MacroAssemblerIA32StackOverflow) {
int end_offset = start_offset + seq_input->length(); int end_offset = start_offset + seq_input->length();
RegExpMacroAssemblerIA32::Result result = RegExpMacroAssemblerIA32::Result result =
RegExpMacroAssemblerIA32::Execute(*code, ExecuteIA32(*code,
seq_input.location(), seq_input.location(),
start_offset, start_offset,
end_offset, end_offset,
NULL, NULL,
true); true);
CHECK_EQ(RegExpMacroAssemblerIA32::EXCEPTION, result); CHECK_EQ(RegExpMacroAssemblerIA32::EXCEPTION, result);
CHECK(Top::has_pending_exception()); CHECK(Top::has_pending_exception());
...@@ -1220,6 +1254,56 @@ TEST(MacroAssemblerIA32StackOverflow) { ...@@ -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 #endif // !defined ARM
TEST(AddInverseToTable) { TEST(AddInverseToTable) {
......
...@@ -300,6 +300,10 @@ ...@@ -300,6 +300,10 @@
RelativePath="..\..\src\regexp-macro-assembler-irregexp-inl.h" RelativePath="..\..\src\regexp-macro-assembler-irregexp-inl.h"
> >
</File> </File>
<File
RelativePath="..\..\src\regexp-stack.h"
>
</File>
<File <File
RelativePath="..\..\src\assembler.cc" RelativePath="..\..\src\assembler.cc"
> >
...@@ -744,6 +748,10 @@ ...@@ -744,6 +748,10 @@
RelativePath="..\..\src\regexp-macro-assembler-tracer.h" RelativePath="..\..\src\regexp-macro-assembler-tracer.h"
> >
</File> </File>
<File
RelativePath="..\..\src\regexp-stack.cc"
>
</File>
<File <File
RelativePath="..\..\src\rewriter.cc" RelativePath="..\..\src\rewriter.cc"
> >
......
...@@ -296,6 +296,10 @@ ...@@ -296,6 +296,10 @@
RelativePath="..\..\src\assembler-arm.h" RelativePath="..\..\src\assembler-arm.h"
> >
</File> </File>
<File
RelativePath="..\..\src\regexp-stack.h"
>
</File>
<File <File
RelativePath="..\..\src\regexp-macro-assembler-irregexp-inl.h" RelativePath="..\..\src\regexp-macro-assembler-irregexp-inl.h"
> >
...@@ -748,6 +752,10 @@ ...@@ -748,6 +752,10 @@
RelativePath="..\..\src\regexp-macro-assembler-tracer.h" RelativePath="..\..\src\regexp-macro-assembler-tracer.h"
> >
</File> </File>
<File
RelativePath="..\..\src\regexp-stack.cc"
>
</File>
<File <File
RelativePath="..\..\src\rewriter.cc" RelativePath="..\..\src\rewriter.cc"
> >
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment