| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 #include "macro-assembler.h" | 36 #include "macro-assembler.h" |
| 37 #include "regexp-macro-assembler.h" | 37 #include "regexp-macro-assembler.h" |
| 38 #include "mips/regexp-macro-assembler-mips.h" | 38 #include "mips/regexp-macro-assembler-mips.h" |
| 39 | 39 |
| 40 namespace v8 { | 40 namespace v8 { |
| 41 namespace internal { | 41 namespace internal { |
| 42 | 42 |
| 43 #ifndef V8_INTERPRETED_REGEXP | 43 #ifndef V8_INTERPRETED_REGEXP |
| 44 /* | 44 /* |
| 45 * This assembler uses the following register assignment convention | 45 * This assembler uses the following register assignment convention |
| 46 * - t7 : Temporarily stores the index of capture start after a matching pass |
| 47 * for a global regexp. |
| 46 * - t1 : Pointer to current code object (Code*) including heap object tag. | 48 * - t1 : Pointer to current code object (Code*) including heap object tag. |
| 47 * - t2 : Current position in input, as negative offset from end of string. | 49 * - t2 : Current position in input, as negative offset from end of string. |
| 48 * Please notice that this is the byte offset, not the character offset! | 50 * Please notice that this is the byte offset, not the character offset! |
| 49 * - t3 : Currently loaded character. Must be loaded using | 51 * - t3 : Currently loaded character. Must be loaded using |
| 50 * LoadCurrentCharacter before using any of the dispatch methods. | 52 * LoadCurrentCharacter before using any of the dispatch methods. |
| 51 * - t4 : points to tip of backtrack stack | 53 * - t4 : Points to tip of backtrack stack |
| 52 * - t5 : Unused. | 54 * - t5 : Unused. |
| 53 * - t6 : End of input (points to byte after last character in input). | 55 * - t6 : End of input (points to byte after last character in input). |
| 54 * - fp : Frame pointer. Used to access arguments, local variables and | 56 * - fp : Frame pointer. Used to access arguments, local variables and |
| 55 * RegExp registers. | 57 * RegExp registers. |
| 56 * - sp : points to tip of C stack. | 58 * - sp : Points to tip of C stack. |
| 57 * | 59 * |
| 58 * The remaining registers are free for computations. | 60 * The remaining registers are free for computations. |
| 59 * Each call to a public method should retain this convention. | 61 * Each call to a public method should retain this convention. |
| 60 * | 62 * |
| 61 * The stack will have the following structure: | 63 * The stack will have the following structure: |
| 62 * | 64 * |
| 63 * - fp[56] direct_call (if 1, direct call from JavaScript code, | 65 * - fp[64] Isolate* isolate (address of the current isolate) |
| 66 * - fp[60] direct_call (if 1, direct call from JavaScript code, |
| 64 * if 0, call through the runtime system). | 67 * if 0, call through the runtime system). |
| 65 * - fp[52] stack_area_base (High end of the memory area to use as | 68 * - fp[56] stack_area_base (High end of the memory area to use as |
| 66 * backtracking stack). | 69 * backtracking stack). |
| 70 * - fp[52] capture array size (may fit multiple sets of matches) |
| 67 * - fp[48] int* capture_array (int[num_saved_registers_], for output). | 71 * - fp[48] int* capture_array (int[num_saved_registers_], for output). |
| 68 * - fp[44] secondary link/return address used by native call. | 72 * - fp[44] secondary link/return address used by native call. |
| 69 * --- sp when called --- | 73 * --- sp when called --- |
| 70 * - fp[40] return address (lr). | 74 * - fp[40] return address (lr). |
| 71 * - fp[36] old frame pointer (r11). | 75 * - fp[36] old frame pointer (r11). |
| 72 * - fp[0..32] backup of registers s0..s7. | 76 * - fp[0..32] backup of registers s0..s7. |
| 73 * --- frame pointer ---- | 77 * --- frame pointer ---- |
| 74 * - fp[-4] end of input (Address of end of string). | 78 * - fp[-4] end of input (address of end of string). |
| 75 * - fp[-8] start of input (Address of first character in string). | 79 * - fp[-8] start of input (address of first character in string). |
| 76 * - fp[-12] start index (character index of start). | 80 * - fp[-12] start index (character index of start). |
| 77 * - fp[-16] void* input_string (location of a handle containing the string). | 81 * - fp[-16] void* input_string (location of a handle containing the string). |
| 78 * - fp[-20] Offset of location before start of input (effectively character | 82 * - fp[-20] success counter (only for global regexps to count matches). |
| 83 * - fp[-24] Offset of location before start of input (effectively character |
| 79 * position -1). Used to initialize capture registers to a | 84 * position -1). Used to initialize capture registers to a |
| 80 * non-position. | 85 * non-position. |
| 81 * - fp[-24] At start (if 1, we are starting at the start of the | 86 * - fp[-28] At start (if 1, we are starting at the start of the |
| 82 * string, otherwise 0) | 87 * string, otherwise 0) |
| 83 * - fp[-28] register 0 (Only positions must be stored in the first | 88 * - fp[-32] register 0 (Only positions must be stored in the first |
| 84 * - register 1 num_saved_registers_ registers) | 89 * - register 1 num_saved_registers_ registers) |
| 85 * - ... | 90 * - ... |
| 86 * - register num_registers-1 | 91 * - register num_registers-1 |
| 87 * --- sp --- | 92 * --- sp --- |
| 88 * | 93 * |
| 89 * The first num_saved_registers_ registers are initialized to point to | 94 * The first num_saved_registers_ registers are initialized to point to |
| 90 * "character -1" in the string (i.e., char_size() bytes before the first | 95 * "character -1" in the string (i.e., char_size() bytes before the first |
| 91 * character of the string). The remaining registers start out as garbage. | 96 * character of the string). The remaining registers start out as garbage. |
| 92 * | 97 * |
| 93 * The data up to the return address must be placed there by the calling | 98 * The data up to the return address must be placed there by the calling |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 | 199 |
| 195 | 200 |
| 196 void RegExpMacroAssemblerMIPS::CheckCharacterGT(uc16 limit, Label* on_greater) { | 201 void RegExpMacroAssemblerMIPS::CheckCharacterGT(uc16 limit, Label* on_greater) { |
| 197 BranchOrBacktrack(on_greater, gt, current_character(), Operand(limit)); | 202 BranchOrBacktrack(on_greater, gt, current_character(), Operand(limit)); |
| 198 } | 203 } |
| 199 | 204 |
| 200 | 205 |
| 201 void RegExpMacroAssemblerMIPS::CheckAtStart(Label* on_at_start) { | 206 void RegExpMacroAssemblerMIPS::CheckAtStart(Label* on_at_start) { |
| 202 Label not_at_start; | 207 Label not_at_start; |
| 203 // Did we start the match at the start of the string at all? | 208 // Did we start the match at the start of the string at all? |
| 204 __ lw(a0, MemOperand(frame_pointer(), kAtStart)); | 209 __ lw(a0, MemOperand(frame_pointer(), kStartIndex)); |
| 205 BranchOrBacktrack(¬_at_start, eq, a0, Operand(zero_reg)); | 210 BranchOrBacktrack(¬_at_start, ne, a0, Operand(zero_reg)); |
| 206 | 211 |
| 207 // If we did, are we still at the start of the input? | 212 // If we did, are we still at the start of the input? |
| 208 __ lw(a1, MemOperand(frame_pointer(), kInputStart)); | 213 __ lw(a1, MemOperand(frame_pointer(), kInputStart)); |
| 209 __ Addu(a0, end_of_input_address(), Operand(current_input_offset())); | 214 __ Addu(a0, end_of_input_address(), Operand(current_input_offset())); |
| 210 BranchOrBacktrack(on_at_start, eq, a0, Operand(a1)); | 215 BranchOrBacktrack(on_at_start, eq, a0, Operand(a1)); |
| 211 __ bind(¬_at_start); | 216 __ bind(¬_at_start); |
| 212 } | 217 } |
| 213 | 218 |
| 214 | 219 |
| 215 void RegExpMacroAssemblerMIPS::CheckNotAtStart(Label* on_not_at_start) { | 220 void RegExpMacroAssemblerMIPS::CheckNotAtStart(Label* on_not_at_start) { |
| 216 // Did we start the match at the start of the string at all? | 221 // Did we start the match at the start of the string at all? |
| 217 __ lw(a0, MemOperand(frame_pointer(), kAtStart)); | 222 __ lw(a0, MemOperand(frame_pointer(), kStartIndex)); |
| 218 BranchOrBacktrack(on_not_at_start, eq, a0, Operand(zero_reg)); | 223 BranchOrBacktrack(on_not_at_start, ne, a0, Operand(zero_reg)); |
| 219 // If we did, are we still at the start of the input? | 224 // If we did, are we still at the start of the input? |
| 220 __ lw(a1, MemOperand(frame_pointer(), kInputStart)); | 225 __ lw(a1, MemOperand(frame_pointer(), kInputStart)); |
| 221 __ Addu(a0, end_of_input_address(), Operand(current_input_offset())); | 226 __ Addu(a0, end_of_input_address(), Operand(current_input_offset())); |
| 222 BranchOrBacktrack(on_not_at_start, ne, a0, Operand(a1)); | 227 BranchOrBacktrack(on_not_at_start, ne, a0, Operand(a1)); |
| 223 } | 228 } |
| 224 | 229 |
| 225 | 230 |
| 226 void RegExpMacroAssemblerMIPS::CheckCharacterLT(uc16 limit, Label* on_less) { | 231 void RegExpMacroAssemblerMIPS::CheckCharacterLT(uc16 limit, Label* on_less) { |
| 227 BranchOrBacktrack(on_less, lt, current_character(), Operand(limit)); | 232 BranchOrBacktrack(on_less, lt, current_character(), Operand(limit)); |
| 228 } | 233 } |
| (...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 633 } | 638 } |
| 634 | 639 |
| 635 | 640 |
| 636 void RegExpMacroAssemblerMIPS::Fail() { | 641 void RegExpMacroAssemblerMIPS::Fail() { |
| 637 __ li(v0, Operand(FAILURE)); | 642 __ li(v0, Operand(FAILURE)); |
| 638 __ jmp(&exit_label_); | 643 __ jmp(&exit_label_); |
| 639 } | 644 } |
| 640 | 645 |
| 641 | 646 |
| 642 Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) { | 647 Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) { |
| 648 Label return_v0; |
| 643 if (masm_->has_exception()) { | 649 if (masm_->has_exception()) { |
| 644 // If the code gets corrupted due to long regular expressions and lack of | 650 // If the code gets corrupted due to long regular expressions and lack of |
| 645 // space on trampolines, an internal exception flag is set. If this case | 651 // space on trampolines, an internal exception flag is set. If this case |
| 646 // is detected, we will jump into exit sequence right away. | 652 // is detected, we will jump into exit sequence right away. |
| 647 __ bind_to(&entry_label_, internal_failure_label_.pos()); | 653 __ bind_to(&entry_label_, internal_failure_label_.pos()); |
| 648 } else { | 654 } else { |
| 649 // Finalize code - write the entry point code now we know how many | 655 // Finalize code - write the entry point code now we know how many |
| 650 // registers we need. | 656 // registers we need. |
| 651 | 657 |
| 652 // Entry code: | 658 // Entry code: |
| 653 __ bind(&entry_label_); | 659 __ bind(&entry_label_); |
| 654 | 660 |
| 655 // Tell the system that we have a stack frame. Because the type is MANUAL, | 661 // Tell the system that we have a stack frame. Because the type is MANUAL, |
| 656 // no is generated. | 662 // no is generated. |
| 657 FrameScope scope(masm_, StackFrame::MANUAL); | 663 FrameScope scope(masm_, StackFrame::MANUAL); |
| 658 | 664 |
| 659 // Actually emit code to start a new stack frame. | 665 // Actually emit code to start a new stack frame. |
| 660 // Push arguments | 666 // Push arguments |
| 661 // Save callee-save registers. | 667 // Save callee-save registers. |
| 662 // Start new stack frame. | 668 // Start new stack frame. |
| 663 // Store link register in existing stack-cell. | 669 // Store link register in existing stack-cell. |
| 664 // Order here should correspond to order of offset constants in header file. | 670 // Order here should correspond to order of offset constants in header file. |
| 665 RegList registers_to_retain = s0.bit() | s1.bit() | s2.bit() | | 671 RegList registers_to_retain = s0.bit() | s1.bit() | s2.bit() | |
| 666 s3.bit() | s4.bit() | s5.bit() | s6.bit() | s7.bit() | fp.bit(); | 672 s3.bit() | s4.bit() | s5.bit() | s6.bit() | s7.bit() | fp.bit(); |
| 667 RegList argument_registers = a0.bit() | a1.bit() | a2.bit() | a3.bit(); | 673 RegList argument_registers = a0.bit() | a1.bit() | a2.bit() | a3.bit(); |
| 668 __ MultiPush(argument_registers | registers_to_retain | ra.bit()); | 674 __ MultiPush(argument_registers | registers_to_retain | ra.bit()); |
| 669 // Set frame pointer in space for it if this is not a direct call | 675 // Set frame pointer in space for it if this is not a direct call |
| 670 // from generated code. | 676 // from generated code. |
| 671 __ Addu(frame_pointer(), sp, Operand(4 * kPointerSize)); | 677 __ Addu(frame_pointer(), sp, Operand(4 * kPointerSize)); |
| 678 __ mov(a0, zero_reg); |
| 679 __ push(a0); // Make room for success counter and initialize it to 0. |
| 672 __ push(a0); // Make room for "position - 1" constant (value irrelevant). | 680 __ push(a0); // Make room for "position - 1" constant (value irrelevant). |
| 673 __ push(a0); // Make room for "at start" constant (value irrelevant). | |
| 674 | 681 |
| 675 // Check if we have space on the stack for registers. | 682 // Check if we have space on the stack for registers. |
| 676 Label stack_limit_hit; | 683 Label stack_limit_hit; |
| 677 Label stack_ok; | 684 Label stack_ok; |
| 678 | 685 |
| 679 ExternalReference stack_limit = | 686 ExternalReference stack_limit = |
| 680 ExternalReference::address_of_stack_limit(masm_->isolate()); | 687 ExternalReference::address_of_stack_limit(masm_->isolate()); |
| 681 __ li(a0, Operand(stack_limit)); | 688 __ li(a0, Operand(stack_limit)); |
| 682 __ lw(a0, MemOperand(a0)); | 689 __ lw(a0, MemOperand(a0)); |
| 683 __ Subu(a0, sp, a0); | 690 __ Subu(a0, sp, a0); |
| 684 // Handle it if the stack pointer is already below the stack limit. | 691 // Handle it if the stack pointer is already below the stack limit. |
| 685 __ Branch(&stack_limit_hit, le, a0, Operand(zero_reg)); | 692 __ Branch(&stack_limit_hit, le, a0, Operand(zero_reg)); |
| 686 // Check if there is room for the variable number of registers above | 693 // Check if there is room for the variable number of registers above |
| 687 // the stack limit. | 694 // the stack limit. |
| 688 __ Branch(&stack_ok, hs, a0, Operand(num_registers_ * kPointerSize)); | 695 __ Branch(&stack_ok, hs, a0, Operand(num_registers_ * kPointerSize)); |
| 689 // Exit with OutOfMemory exception. There is not enough space on the stack | 696 // Exit with OutOfMemory exception. There is not enough space on the stack |
| 690 // for our working registers. | 697 // for our working registers. |
| 691 __ li(v0, Operand(EXCEPTION)); | 698 __ li(v0, Operand(EXCEPTION)); |
| 692 __ jmp(&exit_label_); | 699 __ jmp(&return_v0); |
| 693 | 700 |
| 694 __ bind(&stack_limit_hit); | 701 __ bind(&stack_limit_hit); |
| 695 CallCheckStackGuardState(a0); | 702 CallCheckStackGuardState(a0); |
| 696 // If returned value is non-zero, we exit with the returned value as result. | 703 // If returned value is non-zero, we exit with the returned value as result. |
| 697 __ Branch(&exit_label_, ne, v0, Operand(zero_reg)); | 704 __ Branch(&return_v0, ne, v0, Operand(zero_reg)); |
| 698 | 705 |
| 699 __ bind(&stack_ok); | 706 __ bind(&stack_ok); |
| 700 // Allocate space on stack for registers. | 707 // Allocate space on stack for registers. |
| 701 __ Subu(sp, sp, Operand(num_registers_ * kPointerSize)); | 708 __ Subu(sp, sp, Operand(num_registers_ * kPointerSize)); |
| 702 // Load string end. | 709 // Load string end. |
| 703 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); | 710 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); |
| 704 // Load input start. | 711 // Load input start. |
| 705 __ lw(a0, MemOperand(frame_pointer(), kInputStart)); | 712 __ lw(a0, MemOperand(frame_pointer(), kInputStart)); |
| 706 // Find negative length (offset of start relative to end). | 713 // Find negative length (offset of start relative to end). |
| 707 __ Subu(current_input_offset(), a0, end_of_input_address()); | 714 __ Subu(current_input_offset(), a0, end_of_input_address()); |
| 708 // Set a0 to address of char before start of the input string | 715 // Set a0 to address of char before start of the input string |
| 709 // (effectively string position -1). | 716 // (effectively string position -1). |
| 710 __ lw(a1, MemOperand(frame_pointer(), kStartIndex)); | 717 __ lw(a1, MemOperand(frame_pointer(), kStartIndex)); |
| 711 __ Subu(a0, current_input_offset(), Operand(char_size())); | 718 __ Subu(a0, current_input_offset(), Operand(char_size())); |
| 712 __ sll(t5, a1, (mode_ == UC16) ? 1 : 0); | 719 __ sll(t5, a1, (mode_ == UC16) ? 1 : 0); |
| 713 __ Subu(a0, a0, t5); | 720 __ Subu(a0, a0, t5); |
| 714 // Store this value in a local variable, for use when clearing | 721 // Store this value in a local variable, for use when clearing |
| 715 // position registers. | 722 // position registers. |
| 716 __ sw(a0, MemOperand(frame_pointer(), kInputStartMinusOne)); | 723 __ sw(a0, MemOperand(frame_pointer(), kInputStartMinusOne)); |
| 717 | 724 |
| 718 // Determine whether the start index is zero, that is at the start of the | 725 // Initialize code pointer register |
| 719 // string, and store that value in a local variable. | 726 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); |
| 720 __ mov(t5, a1); | |
| 721 __ li(a1, Operand(1)); | |
| 722 __ Movn(a1, zero_reg, t5); | |
| 723 __ sw(a1, MemOperand(frame_pointer(), kAtStart)); | |
| 724 | 727 |
| 728 Label load_char_start_regexp, start_regexp; |
| 729 // Load newline if index is at start, previous character otherwise. |
| 730 __ Branch(&load_char_start_regexp, ne, a1, Operand(zero_reg)); |
| 731 __ li(current_character(), Operand('\n')); |
| 732 __ jmp(&start_regexp); |
| 733 |
| 734 // Global regexp restarts matching here. |
| 735 __ bind(&load_char_start_regexp); |
| 736 // Load previous char as initial value of current character register. |
| 737 LoadCurrentCharacterUnchecked(-1, 1); |
| 738 __ bind(&start_regexp); |
| 739 |
| 740 // Initialize on-stack registers. |
| 725 if (num_saved_registers_ > 0) { // Always is, if generated from a regexp. | 741 if (num_saved_registers_ > 0) { // Always is, if generated from a regexp. |
| 726 // Fill saved registers with initial value = start offset - 1. | 742 // Fill saved registers with initial value = start offset - 1. |
| 727 | 743 if (num_saved_registers_ > 8) { |
| 728 // Address of register 0. | 744 // Address of register 0. |
| 729 __ Addu(a1, frame_pointer(), Operand(kRegisterZero)); | 745 __ Addu(a1, frame_pointer(), Operand(kRegisterZero)); |
| 730 __ li(a2, Operand(num_saved_registers_)); | 746 __ li(a2, Operand(num_saved_registers_)); |
| 731 Label init_loop; | 747 Label init_loop; |
| 732 __ bind(&init_loop); | 748 __ bind(&init_loop); |
| 733 __ sw(a0, MemOperand(a1)); | 749 __ sw(a0, MemOperand(a1)); |
| 734 __ Addu(a1, a1, Operand(-kPointerSize)); | 750 __ Addu(a1, a1, Operand(-kPointerSize)); |
| 735 __ Subu(a2, a2, Operand(1)); | 751 __ Subu(a2, a2, Operand(1)); |
| 736 __ Branch(&init_loop, ne, a2, Operand(zero_reg)); | 752 __ Branch(&init_loop, ne, a2, Operand(zero_reg)); |
| 753 } else { |
| 754 for (int i = 0; i < num_saved_registers_; i++) { |
| 755 __ sw(a0, register_location(i)); |
| 756 } |
| 757 } |
| 737 } | 758 } |
| 738 | 759 |
| 739 // Initialize backtrack stack pointer. | 760 // Initialize backtrack stack pointer. |
| 740 __ lw(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd)); | 761 __ lw(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd)); |
| 741 // Initialize code pointer register | 762 |
| 742 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); | |
| 743 // Load previous char as initial value of current character register. | |
| 744 Label at_start; | |
| 745 __ lw(a0, MemOperand(frame_pointer(), kAtStart)); | |
| 746 __ Branch(&at_start, ne, a0, Operand(zero_reg)); | |
| 747 LoadCurrentCharacterUnchecked(-1, 1); // Load previous char. | |
| 748 __ jmp(&start_label_); | |
| 749 __ bind(&at_start); | |
| 750 __ li(current_character(), Operand('\n')); | |
| 751 __ jmp(&start_label_); | 763 __ jmp(&start_label_); |
| 752 | 764 |
| 753 | 765 |
| 754 // Exit code: | 766 // Exit code: |
| 755 if (success_label_.is_linked()) { | 767 if (success_label_.is_linked()) { |
| 756 // Save captures when successful. | 768 // Save captures when successful. |
| 757 __ bind(&success_label_); | 769 __ bind(&success_label_); |
| 758 if (num_saved_registers_ > 0) { | 770 if (num_saved_registers_ > 0) { |
| 759 // Copy captures to output. | 771 // Copy captures to output. |
| 760 __ lw(a1, MemOperand(frame_pointer(), kInputStart)); | 772 __ lw(a1, MemOperand(frame_pointer(), kInputStart)); |
| 761 __ lw(a0, MemOperand(frame_pointer(), kRegisterOutput)); | 773 __ lw(a0, MemOperand(frame_pointer(), kRegisterOutput)); |
| 762 __ lw(a2, MemOperand(frame_pointer(), kStartIndex)); | 774 __ lw(a2, MemOperand(frame_pointer(), kStartIndex)); |
| 763 __ Subu(a1, end_of_input_address(), a1); | 775 __ Subu(a1, end_of_input_address(), a1); |
| 764 // a1 is length of input in bytes. | 776 // a1 is length of input in bytes. |
| 765 if (mode_ == UC16) { | 777 if (mode_ == UC16) { |
| 766 __ srl(a1, a1, 1); | 778 __ srl(a1, a1, 1); |
| 767 } | 779 } |
| 768 // a1 is length of input in characters. | 780 // a1 is length of input in characters. |
| 769 __ Addu(a1, a1, Operand(a2)); | 781 __ Addu(a1, a1, Operand(a2)); |
| 770 // a1 is length of string in characters. | 782 // a1 is length of string in characters. |
| 771 | 783 |
| 772 ASSERT_EQ(0, num_saved_registers_ % 2); | 784 ASSERT_EQ(0, num_saved_registers_ % 2); |
| 773 // Always an even number of capture registers. This allows us to | 785 // Always an even number of capture registers. This allows us to |
| 774 // unroll the loop once to add an operation between a load of a register | 786 // unroll the loop once to add an operation between a load of a register |
| 775 // and the following use of that register. | 787 // and the following use of that register. |
| 776 for (int i = 0; i < num_saved_registers_; i += 2) { | 788 for (int i = 0; i < num_saved_registers_; i += 2) { |
| 777 __ lw(a2, register_location(i)); | 789 __ lw(a2, register_location(i)); |
| 778 __ lw(a3, register_location(i + 1)); | 790 __ lw(a3, register_location(i + 1)); |
| 791 if (global()) { |
| 792 // Keep capture start in a4 for the zero-length check later. |
| 793 __ mov(t7, a2); |
| 794 } |
| 779 if (mode_ == UC16) { | 795 if (mode_ == UC16) { |
| 780 __ sra(a2, a2, 1); | 796 __ sra(a2, a2, 1); |
| 781 __ Addu(a2, a2, a1); | 797 __ Addu(a2, a2, a1); |
| 782 __ sra(a3, a3, 1); | 798 __ sra(a3, a3, 1); |
| 783 __ Addu(a3, a3, a1); | 799 __ Addu(a3, a3, a1); |
| 784 } else { | 800 } else { |
| 785 __ Addu(a2, a1, Operand(a2)); | 801 __ Addu(a2, a1, Operand(a2)); |
| 786 __ Addu(a3, a1, Operand(a3)); | 802 __ Addu(a3, a1, Operand(a3)); |
| 787 } | 803 } |
| 788 __ sw(a2, MemOperand(a0)); | 804 __ sw(a2, MemOperand(a0)); |
| 789 __ Addu(a0, a0, kPointerSize); | 805 __ Addu(a0, a0, kPointerSize); |
| 790 __ sw(a3, MemOperand(a0)); | 806 __ sw(a3, MemOperand(a0)); |
| 791 __ Addu(a0, a0, kPointerSize); | 807 __ Addu(a0, a0, kPointerSize); |
| 792 } | 808 } |
| 793 } | 809 } |
| 794 __ li(v0, Operand(SUCCESS)); | 810 |
| 811 if (global()) { |
| 812 // Restart matching if the regular expression is flagged as global. |
| 813 __ lw(a0, MemOperand(frame_pointer(), kSuccessfulCaptures)); |
| 814 __ lw(a1, MemOperand(frame_pointer(), kNumOutputRegisters)); |
| 815 __ lw(a2, MemOperand(frame_pointer(), kRegisterOutput)); |
| 816 // Increment success counter. |
| 817 __ Addu(a0, a0, 1); |
| 818 __ sw(a0, MemOperand(frame_pointer(), kSuccessfulCaptures)); |
| 819 // Capture results have been stored, so the number of remaining global |
| 820 // output registers is reduced by the number of stored captures. |
| 821 __ Subu(a1, a1, num_saved_registers_); |
| 822 // Check whether we have enough room for another set of capture results. |
| 823 __ mov(v0, a0); |
| 824 __ Branch(&return_v0, lt, a1, Operand(num_saved_registers_)); |
| 825 |
| 826 __ sw(a1, MemOperand(frame_pointer(), kNumOutputRegisters)); |
| 827 // Advance the location for output. |
| 828 __ Addu(a2, a2, num_saved_registers_ * kPointerSize); |
| 829 __ sw(a2, MemOperand(frame_pointer(), kRegisterOutput)); |
| 830 |
| 831 // Prepare a0 to initialize registers with its value in the next run. |
| 832 __ lw(a0, MemOperand(frame_pointer(), kInputStartMinusOne)); |
| 833 // Special case for zero-length matches. |
| 834 // t7: capture start index |
| 835 // Not a zero-length match, restart. |
| 836 __ Branch(&load_char_start_regexp, ne, current_input_offset(), Operand(t
7)); |
| 837 // Offset from the end is zero if we already reached the end. |
| 838 __ Branch(&exit_label_, eq, current_input_offset(), Operand(zero_reg)); |
| 839 // Advance current position after a zero-length match. |
| 840 __ Addu(current_input_offset(), |
| 841 current_input_offset(), |
| 842 Operand((mode_ == UC16) ? 2 : 1)); |
| 843 __ Branch(&load_char_start_regexp); |
| 844 } else { |
| 845 __ li(v0, Operand(SUCCESS)); |
| 846 } |
| 795 } | 847 } |
| 796 // Exit and return v0. | 848 // Exit and return v0. |
| 797 __ bind(&exit_label_); | 849 __ bind(&exit_label_); |
| 850 if (global()) { |
| 851 __ lw(v0, MemOperand(frame_pointer(), kSuccessfulCaptures)); |
| 852 } |
| 853 |
| 854 __ bind(&return_v0); |
| 798 // Skip sp past regexp registers and local variables.. | 855 // Skip sp past regexp registers and local variables.. |
| 799 __ mov(sp, frame_pointer()); | 856 __ mov(sp, frame_pointer()); |
| 800 // Restore registers s0..s7 and return (restoring ra to pc). | 857 // Restore registers s0..s7 and return (restoring ra to pc). |
| 801 __ MultiPop(registers_to_retain | ra.bit()); | 858 __ MultiPop(registers_to_retain | ra.bit()); |
| 802 __ Ret(); | 859 __ Ret(); |
| 803 | 860 |
| 804 // Backtrack code (branch target for conditional backtracks). | 861 // Backtrack code (branch target for conditional backtracks). |
| 805 if (backtrack_label_.is_linked()) { | 862 if (backtrack_label_.is_linked()) { |
| 806 __ bind(&backtrack_label_); | 863 __ bind(&backtrack_label_); |
| 807 Backtrack(); | 864 Backtrack(); |
| 808 } | 865 } |
| 809 | 866 |
| 810 Label exit_with_exception; | 867 Label exit_with_exception; |
| 811 | 868 |
| 812 // Preempt-code. | 869 // Preempt-code. |
| 813 if (check_preempt_label_.is_linked()) { | 870 if (check_preempt_label_.is_linked()) { |
| 814 SafeCallTarget(&check_preempt_label_); | 871 SafeCallTarget(&check_preempt_label_); |
| 815 // Put regexp engine registers on stack. | 872 // Put regexp engine registers on stack. |
| 816 RegList regexp_registers_to_retain = current_input_offset().bit() | | 873 RegList regexp_registers_to_retain = current_input_offset().bit() | |
| 817 current_character().bit() | backtrack_stackpointer().bit(); | 874 current_character().bit() | backtrack_stackpointer().bit(); |
| 818 __ MultiPush(regexp_registers_to_retain); | 875 __ MultiPush(regexp_registers_to_retain); |
| 819 CallCheckStackGuardState(a0); | 876 CallCheckStackGuardState(a0); |
| 820 __ MultiPop(regexp_registers_to_retain); | 877 __ MultiPop(regexp_registers_to_retain); |
| 821 // If returning non-zero, we should end execution with the given | 878 // If returning non-zero, we should end execution with the given |
| 822 // result as return value. | 879 // result as return value. |
| 823 __ Branch(&exit_label_, ne, v0, Operand(zero_reg)); | 880 __ Branch(&return_v0, ne, v0, Operand(zero_reg)); |
| 824 | 881 |
| 825 // String might have moved: Reload end of string from frame. | 882 // String might have moved: Reload end of string from frame. |
| 826 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); | 883 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); |
| 827 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); | 884 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); |
| 828 SafeReturn(); | 885 SafeReturn(); |
| 829 } | 886 } |
| 830 | 887 |
| 831 // Backtrack stack overflow code. | 888 // Backtrack stack overflow code. |
| 832 if (stack_overflow_label_.is_linked()) { | 889 if (stack_overflow_label_.is_linked()) { |
| 833 SafeCallTarget(&stack_overflow_label_); | 890 SafeCallTarget(&stack_overflow_label_); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 857 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); | 914 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); |
| 858 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); | 915 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); |
| 859 SafeReturn(); | 916 SafeReturn(); |
| 860 } | 917 } |
| 861 | 918 |
| 862 if (exit_with_exception.is_linked()) { | 919 if (exit_with_exception.is_linked()) { |
| 863 // If any of the code above needed to exit with an exception. | 920 // If any of the code above needed to exit with an exception. |
| 864 __ bind(&exit_with_exception); | 921 __ bind(&exit_with_exception); |
| 865 // Exit with Result EXCEPTION(-1) to signal thrown exception. | 922 // Exit with Result EXCEPTION(-1) to signal thrown exception. |
| 866 __ li(v0, Operand(EXCEPTION)); | 923 __ li(v0, Operand(EXCEPTION)); |
| 867 __ jmp(&exit_label_); | 924 __ jmp(&return_v0); |
| 868 } | 925 } |
| 869 } | 926 } |
| 870 | 927 |
| 871 CodeDesc code_desc; | 928 CodeDesc code_desc; |
| 872 masm_->GetCode(&code_desc); | 929 masm_->GetCode(&code_desc); |
| 873 Handle<Code> code = FACTORY->NewCode(code_desc, | 930 Handle<Code> code = FACTORY->NewCode(code_desc, |
| 874 Code::ComputeFlags(Code::REGEXP), | 931 Code::ComputeFlags(Code::REGEXP), |
| 875 masm_->CodeObject()); | 932 masm_->CodeObject()); |
| 876 LOG(Isolate::Current(), RegExpCodeCreateEvent(*code, *source)); | 933 LOG(Isolate::Current(), RegExpCodeCreateEvent(*code, *source)); |
| 877 return Handle<HeapObject>::cast(code); | 934 return Handle<HeapObject>::cast(code); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1005 } | 1062 } |
| 1006 | 1063 |
| 1007 | 1064 |
| 1008 void RegExpMacroAssemblerMIPS::SetRegister(int register_index, int to) { | 1065 void RegExpMacroAssemblerMIPS::SetRegister(int register_index, int to) { |
| 1009 ASSERT(register_index >= num_saved_registers_); // Reserved for positions! | 1066 ASSERT(register_index >= num_saved_registers_); // Reserved for positions! |
| 1010 __ li(a0, Operand(to)); | 1067 __ li(a0, Operand(to)); |
| 1011 __ sw(a0, register_location(register_index)); | 1068 __ sw(a0, register_location(register_index)); |
| 1012 } | 1069 } |
| 1013 | 1070 |
| 1014 | 1071 |
| 1015 void RegExpMacroAssemblerMIPS::Succeed() { | 1072 bool RegExpMacroAssemblerMIPS::Succeed() { |
| 1016 __ jmp(&success_label_); | 1073 __ jmp(&success_label_); |
| 1074 return global(); |
| 1017 } | 1075 } |
| 1018 | 1076 |
| 1019 | 1077 |
| 1020 void RegExpMacroAssemblerMIPS::WriteCurrentPositionToRegister(int reg, | 1078 void RegExpMacroAssemblerMIPS::WriteCurrentPositionToRegister(int reg, |
| 1021 int cp_offset) { | 1079 int cp_offset) { |
| 1022 if (cp_offset == 0) { | 1080 if (cp_offset == 0) { |
| 1023 __ sw(current_input_offset(), register_location(reg)); | 1081 __ sw(current_input_offset(), register_location(reg)); |
| 1024 } else { | 1082 } else { |
| 1025 __ Addu(a0, current_input_offset(), Operand(cp_offset * char_size())); | 1083 __ Addu(a0, current_input_offset(), Operand(cp_offset * char_size())); |
| 1026 __ sw(a0, register_location(reg)); | 1084 __ sw(a0, register_location(reg)); |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1273 __ lw(sp, MemOperand(sp, 16)); | 1331 __ lw(sp, MemOperand(sp, 16)); |
| 1274 } | 1332 } |
| 1275 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); | 1333 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); |
| 1276 } | 1334 } |
| 1277 | 1335 |
| 1278 | 1336 |
| 1279 void RegExpMacroAssemblerMIPS::LoadCurrentCharacterUnchecked(int cp_offset, | 1337 void RegExpMacroAssemblerMIPS::LoadCurrentCharacterUnchecked(int cp_offset, |
| 1280 int characters) { | 1338 int characters) { |
| 1281 Register offset = current_input_offset(); | 1339 Register offset = current_input_offset(); |
| 1282 if (cp_offset != 0) { | 1340 if (cp_offset != 0) { |
| 1283 __ Addu(a0, current_input_offset(), Operand(cp_offset * char_size())); | 1341 // t7 is not being used to store the capture start index at this point. |
| 1284 offset = a0; | 1342 __ Addu(t7, current_input_offset(), Operand(cp_offset * char_size())); |
| 1343 offset = t7; |
| 1285 } | 1344 } |
| 1286 // We assume that we cannot do unaligned loads on MIPS, so this function | 1345 // We assume that we cannot do unaligned loads on MIPS, so this function |
| 1287 // must only be used to load a single character at a time. | 1346 // must only be used to load a single character at a time. |
| 1288 ASSERT(characters == 1); | 1347 ASSERT(characters == 1); |
| 1289 __ Addu(t5, end_of_input_address(), Operand(offset)); | 1348 __ Addu(t5, end_of_input_address(), Operand(offset)); |
| 1290 if (mode_ == ASCII) { | 1349 if (mode_ == ASCII) { |
| 1291 __ lbu(current_character(), MemOperand(t5, 0)); | 1350 __ lbu(current_character(), MemOperand(t5, 0)); |
| 1292 } else { | 1351 } else { |
| 1293 ASSERT(mode_ == UC16); | 1352 ASSERT(mode_ == UC16); |
| 1294 __ lhu(current_character(), MemOperand(t5, 0)); | 1353 __ lhu(current_character(), MemOperand(t5, 0)); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1313 } | 1372 } |
| 1314 | 1373 |
| 1315 | 1374 |
| 1316 #undef __ | 1375 #undef __ |
| 1317 | 1376 |
| 1318 #endif // V8_INTERPRETED_REGEXP | 1377 #endif // V8_INTERPRETED_REGEXP |
| 1319 | 1378 |
| 1320 }} // namespace v8::internal | 1379 }} // namespace v8::internal |
| 1321 | 1380 |
| 1322 #endif // V8_TARGET_ARCH_MIPS | 1381 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |