| Index: src/mips/regexp-macro-assembler-mips.cc
|
| diff --git a/src/mips/regexp-macro-assembler-mips.cc b/src/mips/regexp-macro-assembler-mips.cc
|
| index c48bcc497e7c03ee1aea544b58e59303e275152a..5e9aeedc90568185ab7b309f8ba1ec1b97287a2a 100644
|
| --- a/src/mips/regexp-macro-assembler-mips.cc
|
| +++ b/src/mips/regexp-macro-assembler-mips.cc
|
| @@ -43,44 +43,49 @@ namespace internal {
|
| #ifndef V8_INTERPRETED_REGEXP
|
| /*
|
| * This assembler uses the following register assignment convention
|
| + * - t7 : Temporarily stores the index of capture start after a matching pass
|
| + * for a global regexp.
|
| * - t1 : Pointer to current code object (Code*) including heap object tag.
|
| * - t2 : Current position in input, as negative offset from end of string.
|
| * Please notice that this is the byte offset, not the character offset!
|
| * - t3 : Currently loaded character. Must be loaded using
|
| * LoadCurrentCharacter before using any of the dispatch methods.
|
| - * - t4 : points to tip of backtrack stack
|
| + * - t4 : Points to tip of backtrack stack
|
| * - t5 : Unused.
|
| * - t6 : End of input (points to byte after last character in input).
|
| * - fp : Frame pointer. Used to access arguments, local variables and
|
| * RegExp registers.
|
| - * - sp : points to tip of C stack.
|
| + * - sp : Points to tip of C stack.
|
| *
|
| * The remaining registers are free for computations.
|
| * Each call to a public method should retain this convention.
|
| *
|
| * The stack will have the following structure:
|
| *
|
| - * - fp[56] direct_call (if 1, direct call from JavaScript code,
|
| + * - fp[64] Isolate* isolate (address of the current isolate)
|
| + * - fp[60] direct_call (if 1, direct call from JavaScript code,
|
| * if 0, call through the runtime system).
|
| - * - fp[52] stack_area_base (High end of the memory area to use as
|
| + * - fp[56] stack_area_base (High end of the memory area to use as
|
| * backtracking stack).
|
| + * - fp[52] capture array size (may fit multiple sets of matches)
|
| * - fp[48] int* capture_array (int[num_saved_registers_], for output).
|
| * - fp[44] secondary link/return address used by native call.
|
| * --- sp when called ---
|
| - * - fp[40] return address (lr).
|
| - * - fp[36] old frame pointer (r11).
|
| + * - fp[40] return address (lr).
|
| + * - fp[36] old frame pointer (r11).
|
| * - fp[0..32] backup of registers s0..s7.
|
| * --- frame pointer ----
|
| - * - fp[-4] end of input (Address of end of string).
|
| - * - fp[-8] start of input (Address of first character in string).
|
| + * - fp[-4] end of input (address of end of string).
|
| + * - fp[-8] start of input (address of first character in string).
|
| * - fp[-12] start index (character index of start).
|
| * - fp[-16] void* input_string (location of a handle containing the string).
|
| - * - fp[-20] Offset of location before start of input (effectively character
|
| + * - fp[-20] success counter (only for global regexps to count matches).
|
| + * - fp[-24] Offset of location before start of input (effectively character
|
| * position -1). Used to initialize capture registers to a
|
| * non-position.
|
| - * - fp[-24] At start (if 1, we are starting at the start of the
|
| + * - fp[-28] At start (if 1, we are starting at the start of the
|
| * string, otherwise 0)
|
| - * - fp[-28] register 0 (Only positions must be stored in the first
|
| + * - fp[-32] register 0 (Only positions must be stored in the first
|
| * - register 1 num_saved_registers_ registers)
|
| * - ...
|
| * - register num_registers-1
|
| @@ -201,8 +206,8 @@ void RegExpMacroAssemblerMIPS::CheckCharacterGT(uc16 limit, Label* on_greater) {
|
| void RegExpMacroAssemblerMIPS::CheckAtStart(Label* on_at_start) {
|
| Label not_at_start;
|
| // Did we start the match at the start of the string at all?
|
| - __ lw(a0, MemOperand(frame_pointer(), kAtStart));
|
| - BranchOrBacktrack(¬_at_start, eq, a0, Operand(zero_reg));
|
| + __ lw(a0, MemOperand(frame_pointer(), kStartIndex));
|
| + BranchOrBacktrack(¬_at_start, ne, a0, Operand(zero_reg));
|
|
|
| // If we did, are we still at the start of the input?
|
| __ lw(a1, MemOperand(frame_pointer(), kInputStart));
|
| @@ -214,8 +219,8 @@ void RegExpMacroAssemblerMIPS::CheckAtStart(Label* on_at_start) {
|
|
|
| void RegExpMacroAssemblerMIPS::CheckNotAtStart(Label* on_not_at_start) {
|
| // Did we start the match at the start of the string at all?
|
| - __ lw(a0, MemOperand(frame_pointer(), kAtStart));
|
| - BranchOrBacktrack(on_not_at_start, eq, a0, Operand(zero_reg));
|
| + __ lw(a0, MemOperand(frame_pointer(), kStartIndex));
|
| + BranchOrBacktrack(on_not_at_start, ne, a0, Operand(zero_reg));
|
| // If we did, are we still at the start of the input?
|
| __ lw(a1, MemOperand(frame_pointer(), kInputStart));
|
| __ Addu(a0, end_of_input_address(), Operand(current_input_offset()));
|
| @@ -640,6 +645,7 @@ void RegExpMacroAssemblerMIPS::Fail() {
|
|
|
|
|
| Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
|
| + Label return_v0;
|
| if (masm_->has_exception()) {
|
| // If the code gets corrupted due to long regular expressions and lack of
|
| // space on trampolines, an internal exception flag is set. If this case
|
| @@ -669,8 +675,9 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
|
| // Set frame pointer in space for it if this is not a direct call
|
| // from generated code.
|
| __ Addu(frame_pointer(), sp, Operand(4 * kPointerSize));
|
| + __ mov(a0, zero_reg);
|
| + __ push(a0); // Make room for success counter and initialize it to 0.
|
| __ push(a0); // Make room for "position - 1" constant (value irrelevant).
|
| - __ push(a0); // Make room for "at start" constant (value irrelevant).
|
|
|
| // Check if we have space on the stack for registers.
|
| Label stack_limit_hit;
|
| @@ -689,12 +696,12 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
|
| // Exit with OutOfMemory exception. There is not enough space on the stack
|
| // for our working registers.
|
| __ li(v0, Operand(EXCEPTION));
|
| - __ jmp(&exit_label_);
|
| + __ jmp(&return_v0);
|
|
|
| __ bind(&stack_limit_hit);
|
| CallCheckStackGuardState(a0);
|
| // If returned value is non-zero, we exit with the returned value as result.
|
| - __ Branch(&exit_label_, ne, v0, Operand(zero_reg));
|
| + __ Branch(&return_v0, ne, v0, Operand(zero_reg));
|
|
|
| __ bind(&stack_ok);
|
| // Allocate space on stack for registers.
|
| @@ -715,39 +722,44 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
|
| // position registers.
|
| __ sw(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
|
|
|
| - // Determine whether the start index is zero, that is at the start of the
|
| - // string, and store that value in a local variable.
|
| - __ mov(t5, a1);
|
| - __ li(a1, Operand(1));
|
| - __ Movn(a1, zero_reg, t5);
|
| - __ sw(a1, MemOperand(frame_pointer(), kAtStart));
|
| + // Initialize code pointer register
|
| + __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
|
| +
|
| + Label load_char_start_regexp, start_regexp;
|
| + // Load newline if index is at start, previous character otherwise.
|
| + __ Branch(&load_char_start_regexp, ne, a1, Operand(zero_reg));
|
| + __ li(current_character(), Operand('\n'));
|
| + __ jmp(&start_regexp);
|
| +
|
| + // Global regexp restarts matching here.
|
| + __ bind(&load_char_start_regexp);
|
| + // Load previous char as initial value of current character register.
|
| + LoadCurrentCharacterUnchecked(-1, 1);
|
| + __ bind(&start_regexp);
|
|
|
| + // Initialize on-stack registers.
|
| if (num_saved_registers_ > 0) { // Always is, if generated from a regexp.
|
| // Fill saved registers with initial value = start offset - 1.
|
| -
|
| - // Address of register 0.
|
| - __ Addu(a1, frame_pointer(), Operand(kRegisterZero));
|
| - __ li(a2, Operand(num_saved_registers_));
|
| - Label init_loop;
|
| - __ bind(&init_loop);
|
| - __ sw(a0, MemOperand(a1));
|
| - __ Addu(a1, a1, Operand(-kPointerSize));
|
| - __ Subu(a2, a2, Operand(1));
|
| - __ Branch(&init_loop, ne, a2, Operand(zero_reg));
|
| + if (num_saved_registers_ > 8) {
|
| + // Address of register 0.
|
| + __ Addu(a1, frame_pointer(), Operand(kRegisterZero));
|
| + __ li(a2, Operand(num_saved_registers_));
|
| + Label init_loop;
|
| + __ bind(&init_loop);
|
| + __ sw(a0, MemOperand(a1));
|
| + __ Addu(a1, a1, Operand(-kPointerSize));
|
| + __ Subu(a2, a2, Operand(1));
|
| + __ Branch(&init_loop, ne, a2, Operand(zero_reg));
|
| + } else {
|
| + for (int i = 0; i < num_saved_registers_; i++) {
|
| + __ sw(a0, register_location(i));
|
| + }
|
| + }
|
| }
|
|
|
| // Initialize backtrack stack pointer.
|
| __ lw(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd));
|
| - // Initialize code pointer register
|
| - __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
|
| - // Load previous char as initial value of current character register.
|
| - Label at_start;
|
| - __ lw(a0, MemOperand(frame_pointer(), kAtStart));
|
| - __ Branch(&at_start, ne, a0, Operand(zero_reg));
|
| - LoadCurrentCharacterUnchecked(-1, 1); // Load previous char.
|
| - __ jmp(&start_label_);
|
| - __ bind(&at_start);
|
| - __ li(current_character(), Operand('\n'));
|
| +
|
| __ jmp(&start_label_);
|
|
|
|
|
| @@ -776,6 +788,10 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
|
| for (int i = 0; i < num_saved_registers_; i += 2) {
|
| __ lw(a2, register_location(i));
|
| __ lw(a3, register_location(i + 1));
|
| + if (global()) {
|
| + // Keep capture start in a4 for the zero-length check later.
|
| + __ mov(t7, a2);
|
| + }
|
| if (mode_ == UC16) {
|
| __ sra(a2, a2, 1);
|
| __ Addu(a2, a2, a1);
|
| @@ -791,10 +807,51 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
|
| __ Addu(a0, a0, kPointerSize);
|
| }
|
| }
|
| - __ li(v0, Operand(SUCCESS));
|
| +
|
| + if (global()) {
|
| + // Restart matching if the regular expression is flagged as global.
|
| + __ lw(a0, MemOperand(frame_pointer(), kSuccessfulCaptures));
|
| + __ lw(a1, MemOperand(frame_pointer(), kNumOutputRegisters));
|
| + __ lw(a2, MemOperand(frame_pointer(), kRegisterOutput));
|
| + // Increment success counter.
|
| + __ Addu(a0, a0, 1);
|
| + __ sw(a0, MemOperand(frame_pointer(), kSuccessfulCaptures));
|
| + // Capture results have been stored, so the number of remaining global
|
| + // output registers is reduced by the number of stored captures.
|
| + __ Subu(a1, a1, num_saved_registers_);
|
| + // Check whether we have enough room for another set of capture results.
|
| + __ mov(v0, a0);
|
| + __ Branch(&return_v0, lt, a1, Operand(num_saved_registers_));
|
| +
|
| + __ sw(a1, MemOperand(frame_pointer(), kNumOutputRegisters));
|
| + // Advance the location for output.
|
| + __ Addu(a2, a2, num_saved_registers_ * kPointerSize);
|
| + __ sw(a2, MemOperand(frame_pointer(), kRegisterOutput));
|
| +
|
| + // Prepare a0 to initialize registers with its value in the next run.
|
| + __ lw(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
|
| + // Special case for zero-length matches.
|
| + // t7: capture start index
|
| + // Not a zero-length match, restart.
|
| + __ Branch(&load_char_start_regexp, ne, current_input_offset(), Operand(t7));
|
| + // Offset from the end is zero if we already reached the end.
|
| + __ Branch(&exit_label_, eq, current_input_offset(), Operand(zero_reg));
|
| + // Advance current position after a zero-length match.
|
| + __ Addu(current_input_offset(),
|
| + current_input_offset(),
|
| + Operand((mode_ == UC16) ? 2 : 1));
|
| + __ Branch(&load_char_start_regexp);
|
| + } else {
|
| + __ li(v0, Operand(SUCCESS));
|
| + }
|
| }
|
| // Exit and return v0.
|
| __ bind(&exit_label_);
|
| + if (global()) {
|
| + __ lw(v0, MemOperand(frame_pointer(), kSuccessfulCaptures));
|
| + }
|
| +
|
| + __ bind(&return_v0);
|
| // Skip sp past regexp registers and local variables..
|
| __ mov(sp, frame_pointer());
|
| // Restore registers s0..s7 and return (restoring ra to pc).
|
| @@ -820,7 +877,7 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
|
| __ MultiPop(regexp_registers_to_retain);
|
| // If returning non-zero, we should end execution with the given
|
| // result as return value.
|
| - __ Branch(&exit_label_, ne, v0, Operand(zero_reg));
|
| + __ Branch(&return_v0, ne, v0, Operand(zero_reg));
|
|
|
| // String might have moved: Reload end of string from frame.
|
| __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
|
| @@ -864,7 +921,7 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
|
| __ bind(&exit_with_exception);
|
| // Exit with Result EXCEPTION(-1) to signal thrown exception.
|
| __ li(v0, Operand(EXCEPTION));
|
| - __ jmp(&exit_label_);
|
| + __ jmp(&return_v0);
|
| }
|
| }
|
|
|
| @@ -1012,8 +1069,9 @@ void RegExpMacroAssemblerMIPS::SetRegister(int register_index, int to) {
|
| }
|
|
|
|
|
| -void RegExpMacroAssemblerMIPS::Succeed() {
|
| +bool RegExpMacroAssemblerMIPS::Succeed() {
|
| __ jmp(&success_label_);
|
| + return global();
|
| }
|
|
|
|
|
| @@ -1280,8 +1338,9 @@ void RegExpMacroAssemblerMIPS::LoadCurrentCharacterUnchecked(int cp_offset,
|
| int characters) {
|
| Register offset = current_input_offset();
|
| if (cp_offset != 0) {
|
| - __ Addu(a0, current_input_offset(), Operand(cp_offset * char_size()));
|
| - offset = a0;
|
| + // t7 is not being used to store the capture start index at this point.
|
| + __ Addu(t7, current_input_offset(), Operand(cp_offset * char_size()));
|
| + offset = t7;
|
| }
|
| // We assume that we cannot do unaligned loads on MIPS, so this function
|
| // must only be used to load a single character at a time.
|
|
|