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 = {
'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',
......
......@@ -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));
}
......
......@@ -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();
......
......@@ -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);
}
}
}
......
......@@ -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);
}
}
......
......@@ -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_;
};
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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);
......
......@@ -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
......@@ -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;
......
// 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 @@
#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;
}
......
......@@ -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) {
......
......@@ -300,6 +300,10 @@
RelativePath="..\..\src\regexp-macro-assembler-irregexp-inl.h"
>
</File>
<File
RelativePath="..\..\src\regexp-stack.h"
>
</File>
<File
RelativePath="..\..\src\assembler.cc"
>
......@@ -744,6 +748,10 @@
RelativePath="..\..\src\regexp-macro-assembler-tracer.h"
>
</File>
<File
RelativePath="..\..\src\regexp-stack.cc"
>
</File>
<File
RelativePath="..\..\src\rewriter.cc"
>
......
......@@ -296,6 +296,10 @@
RelativePath="..\..\src\assembler-arm.h"
>
</File>
<File
RelativePath="..\..\src\regexp-stack.h"
>
</File>
<File
RelativePath="..\..\src\regexp-macro-assembler-irregexp-inl.h"
>
......@@ -748,6 +752,10 @@
RelativePath="..\..\src\regexp-macro-assembler-tracer.h"
>
</File>
<File
RelativePath="..\..\src\regexp-stack.cc"
>
</File>
<File
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