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 |