diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index 7175fec148..a464348fa7 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc @@ -5043,7 +5043,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { 1, a0, a2); // Isolates: note we add an additional parameter here (isolate pointer). - const int kRegExpExecuteArguments = 8; + const int kRegExpExecuteArguments = 9; const int kParameterRegisters = 4; __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters); @@ -5054,27 +5054,33 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // allocating space for the c argument slots, we don't need to calculate // that into the argument positions on the stack. This is how the stack will // look (sp meaning the value of sp at this moment): + // [sp + 5] - Argument 9 // [sp + 4] - Argument 8 // [sp + 3] - Argument 7 // [sp + 2] - Argument 6 // [sp + 1] - Argument 5 // [sp + 0] - saved ra - // Argument 8: Pass current isolate address. + // Argument 9: Pass current isolate address. // CFunctionArgumentOperand handles MIPS stack argument slots. __ li(a0, Operand(ExternalReference::isolate_address())); + __ sw(a0, MemOperand(sp, 5 * kPointerSize)); + + // Argument 8: Indicate that this is a direct call from JavaScript. + __ li(a0, Operand(1)); __ sw(a0, MemOperand(sp, 4 * kPointerSize)); - // Argument 7: Indicate that this is a direct call from JavaScript. - __ li(a0, Operand(1)); - __ sw(a0, MemOperand(sp, 3 * kPointerSize)); - - // Argument 6: Start (high end) of backtracking stack memory area. + // Argument 7: Start (high end) of backtracking stack memory area. __ li(a0, Operand(address_of_regexp_stack_memory_address)); __ lw(a0, MemOperand(a0, 0)); __ li(a2, Operand(address_of_regexp_stack_memory_size)); __ lw(a2, MemOperand(a2, 0)); __ addu(a0, a0, a2); + __ sw(a0, MemOperand(sp, 3 * kPointerSize)); + + // Argument 6: Set the number of capture registers to zero to force global + // regexps to behave as non-global. This does not affect non-global regexps. + __ mov(a0, zero_reg); __ sw(a0, MemOperand(sp, 2 * kPointerSize)); // Argument 5: static offsets vector buffer. @@ -5125,7 +5131,9 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Check the result. Label success; - __ Branch(&success, eq, v0, Operand(NativeRegExpMacroAssembler::SUCCESS)); + __ Branch(&success, eq, v0, Operand(1)); + // We expect exactly one result since we force the called regexp to behave + // as non-global. Label failure; __ Branch(&failure, eq, v0, Operand(NativeRegExpMacroAssembler::FAILURE)); // If not exception it can only be retry. Handle that in the runtime system. diff --git a/src/mips/regexp-macro-assembler-mips.cc b/src/mips/regexp-macro-assembler-mips.cc index c48bcc497e..5e9aeedc90 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 RegExpMacroAssemblerMIPS::GetCode(Handle 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 RegExpMacroAssemblerMIPS::GetCode(Handle 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 RegExpMacroAssemblerMIPS::GetCode(Handle 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 RegExpMacroAssemblerMIPS::GetCode(Handle 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 RegExpMacroAssemblerMIPS::GetCode(Handle 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 RegExpMacroAssemblerMIPS::GetCode(Handle 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 RegExpMacroAssemblerMIPS::GetCode(Handle 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 RegExpMacroAssemblerMIPS::GetCode(Handle 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. diff --git a/src/mips/regexp-macro-assembler-mips.h b/src/mips/regexp-macro-assembler-mips.h index d167f624b6..562d3fcd76 100644 --- a/src/mips/regexp-macro-assembler-mips.h +++ b/src/mips/regexp-macro-assembler-mips.h @@ -115,7 +115,7 @@ class RegExpMacroAssemblerMIPS: public NativeRegExpMacroAssembler { virtual void ReadStackPointerFromRegister(int reg); virtual void SetCurrentPositionFromEnd(int by); virtual void SetRegister(int register_index, int to); - virtual void Succeed(); + virtual bool Succeed(); virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); virtual void ClearRegisters(int reg_from, int reg_to); virtual void WriteStackPointerToRegister(int reg); @@ -141,7 +141,8 @@ class RegExpMacroAssemblerMIPS: public NativeRegExpMacroAssembler { static const int kStackFrameHeader = kReturnAddress + kPointerSize; // Stack parameters placed by caller. static const int kRegisterOutput = kStackFrameHeader + 20; - static const int kStackHighEnd = kRegisterOutput + kPointerSize; + static const int kNumOutputRegisters = kRegisterOutput + kPointerSize; + static const int kStackHighEnd = kNumOutputRegisters + kPointerSize; static const int kDirectCall = kStackHighEnd + kPointerSize; static const int kIsolate = kDirectCall + kPointerSize; @@ -153,10 +154,10 @@ class RegExpMacroAssemblerMIPS: public NativeRegExpMacroAssembler { static const int kInputString = kStartIndex - kPointerSize; // When adding local variables remember to push space for them in // the frame in GetCode. - static const int kInputStartMinusOne = kInputString - kPointerSize; - static const int kAtStart = kInputStartMinusOne - kPointerSize; + static const int kSuccessfulCaptures = kInputString - kPointerSize; + static const int kInputStartMinusOne = kSuccessfulCaptures - kPointerSize; // First register address. Following registers are below it on the stack. - static const int kRegisterZero = kAtStart - kPointerSize; + static const int kRegisterZero = kInputStartMinusOne - kPointerSize; // Initial size of code buffer. static const size_t kRegExpCodeSize = 1024; diff --git a/src/mips/simulator-mips.h b/src/mips/simulator-mips.h index 1e72939876..776badc29b 100644 --- a/src/mips/simulator-mips.h +++ b/src/mips/simulator-mips.h @@ -50,16 +50,16 @@ namespace internal { entry(p0, p1, p2, p3, p4) typedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*, - void*, int*, Address, int, Isolate*); + void*, int*, int, Address, int, Isolate*); // Call the generated regexp code directly. The code at the entry address // should act as a function matching the type arm_regexp_matcher. // The fifth argument is a dummy that reserves the space used for // the return address added by the ExitFrame in native calls. -#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \ +#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \ (FUNCTION_CAST(entry)( \ - p0, p1, p2, p3, NULL, p4, p5, p6, p7)) + p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)) #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ reinterpret_cast(try_catch_address) @@ -403,9 +403,9 @@ class Simulator { reinterpret_cast(Simulator::current(Isolate::Current())->Call( \ FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4)) -#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \ +#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \ Simulator::current(Isolate::Current())->Call( \ - entry, 9, p0, p1, p2, p3, NULL, p4, p5, p6, p7) + entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8) #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ try_catch_address == NULL ? \