• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "v8.h"
29 
30 #if defined(V8_TARGET_ARCH_MIPS)
31 
32 #include "unicode.h"
33 #include "log.h"
34 #include "code-stubs.h"
35 #include "regexp-stack.h"
36 #include "macro-assembler.h"
37 #include "regexp-macro-assembler.h"
38 #include "mips/regexp-macro-assembler-mips.h"
39 
40 namespace v8 {
41 namespace internal {
42 
43 #ifndef V8_INTERPRETED_REGEXP
44 /*
45  * This assembler uses the following register assignment convention
46  * - t1 : Pointer to current code object (Code*) including heap object tag.
47  * - 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!
49  * - t3 : Currently loaded character. Must be loaded using
50  *        LoadCurrentCharacter before using any of the dispatch methods.
51  * - t4 : points to tip of backtrack stack
52  * - t5 : Unused.
53  * - t6 : End of input (points to byte after last character in input).
54  * - fp : Frame pointer. Used to access arguments, local variables and
55  *         RegExp registers.
56  * - sp : points to tip of C stack.
57  *
58  * The remaining registers are free for computations.
59  * Each call to a public method should retain this convention.
60  *
61  * The stack will have the following structure:
62  *
63  *  - fp[56]  direct_call  (if 1, direct call from JavaScript code,
64  *                          if 0, call through the runtime system).
65  *  - fp[52]  stack_area_base (High end of the memory area to use as
66  *                             backtracking stack).
67  *  - fp[48]  int* capture_array (int[num_saved_registers_], for output).
68  *  - fp[44]  secondary link/return address used by native call.
69  *  --- sp when called ---
70  *  - fp[40]  return address (lr).
71  *  - fp[36]  old frame pointer (r11).
72  *  - fp[0..32]  backup of registers s0..s7.
73  *  --- frame pointer ----
74  *  - fp[-4]  end of input       (Address of end of string).
75  *  - fp[-8]  start of input     (Address of first character in string).
76  *  - fp[-12] start index        (character index of start).
77  *  - fp[-16] void* input_string (location of a handle containing the string).
78  *  - fp[-20] Offset of location before start of input (effectively character
79  *            position -1). Used to initialize capture registers to a
80  *            non-position.
81  *  - fp[-24] At start (if 1, we are starting at the start of the
82  *    string, otherwise 0)
83  *  - fp[-28] register 0         (Only positions must be stored in the first
84  *  -         register 1          num_saved_registers_ registers)
85  *  -         ...
86  *  -         register num_registers-1
87  *  --- sp ---
88  *
89  * 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
91  * character of the string). The remaining registers start out as garbage.
92  *
93  * The data up to the return address must be placed there by the calling
94  * code and the remaining arguments are passed in registers, e.g. by calling the
95  * code entry as cast to a function with the signature:
96  * int (*match)(String* input_string,
97  *              int start_index,
98  *              Address start,
99  *              Address end,
100  *              Address secondary_return_address,  // Only used by native call.
101  *              int* capture_output_array,
102  *              byte* stack_area_base,
103  *              bool direct_call = false)
104  * The call is performed by NativeRegExpMacroAssembler::Execute()
105  * (in regexp-macro-assembler.cc) via the CALL_GENERATED_REGEXP_CODE macro
106  * in mips/simulator-mips.h.
107  * When calling as a non-direct call (i.e., from C++ code), the return address
108  * area is overwritten with the ra register by the RegExp code. When doing a
109  * direct call from generated code, the return address is placed there by
110  * the calling code, as in a normal exit frame.
111  */
112 
113 #define __ ACCESS_MASM(masm_)
114 
RegExpMacroAssemblerMIPS(Mode mode,int registers_to_save)115 RegExpMacroAssemblerMIPS::RegExpMacroAssemblerMIPS(
116     Mode mode,
117     int registers_to_save)
118     : masm_(new MacroAssembler(Isolate::Current(), NULL, kRegExpCodeSize)),
119       mode_(mode),
120       num_registers_(registers_to_save),
121       num_saved_registers_(registers_to_save),
122       entry_label_(),
123       start_label_(),
124       success_label_(),
125       backtrack_label_(),
126       exit_label_(),
127       internal_failure_label_() {
128   ASSERT_EQ(0, registers_to_save % 2);
129   __ jmp(&entry_label_);   // We'll write the entry code later.
130   // If the code gets too big or corrupted, an internal exception will be
131   // raised, and we will exit right away.
132   __ bind(&internal_failure_label_);
133   __ li(v0, Operand(FAILURE));
134   __ Ret();
135   __ bind(&start_label_);  // And then continue from here.
136 }
137 
138 
~RegExpMacroAssemblerMIPS()139 RegExpMacroAssemblerMIPS::~RegExpMacroAssemblerMIPS() {
140   delete masm_;
141   // Unuse labels in case we throw away the assembler without calling GetCode.
142   entry_label_.Unuse();
143   start_label_.Unuse();
144   success_label_.Unuse();
145   backtrack_label_.Unuse();
146   exit_label_.Unuse();
147   check_preempt_label_.Unuse();
148   stack_overflow_label_.Unuse();
149   internal_failure_label_.Unuse();
150 }
151 
152 
stack_limit_slack()153 int RegExpMacroAssemblerMIPS::stack_limit_slack()  {
154   return RegExpStack::kStackLimitSlack;
155 }
156 
157 
AdvanceCurrentPosition(int by)158 void RegExpMacroAssemblerMIPS::AdvanceCurrentPosition(int by) {
159   if (by != 0) {
160     __ Addu(current_input_offset(),
161            current_input_offset(), Operand(by * char_size()));
162   }
163 }
164 
165 
AdvanceRegister(int reg,int by)166 void RegExpMacroAssemblerMIPS::AdvanceRegister(int reg, int by) {
167   ASSERT(reg >= 0);
168   ASSERT(reg < num_registers_);
169   if (by != 0) {
170     __ lw(a0, register_location(reg));
171     __ Addu(a0, a0, Operand(by));
172     __ sw(a0, register_location(reg));
173   }
174 }
175 
176 
Backtrack()177 void RegExpMacroAssemblerMIPS::Backtrack() {
178   CheckPreemption();
179   // Pop Code* offset from backtrack stack, add Code* and jump to location.
180   Pop(a0);
181   __ Addu(a0, a0, code_pointer());
182   __ Jump(a0);
183 }
184 
185 
Bind(Label * label)186 void RegExpMacroAssemblerMIPS::Bind(Label* label) {
187   __ bind(label);
188 }
189 
190 
CheckCharacter(uint32_t c,Label * on_equal)191 void RegExpMacroAssemblerMIPS::CheckCharacter(uint32_t c, Label* on_equal) {
192   BranchOrBacktrack(on_equal, eq, current_character(), Operand(c));
193 }
194 
195 
CheckCharacterGT(uc16 limit,Label * on_greater)196 void RegExpMacroAssemblerMIPS::CheckCharacterGT(uc16 limit, Label* on_greater) {
197   BranchOrBacktrack(on_greater, gt, current_character(), Operand(limit));
198 }
199 
200 
CheckAtStart(Label * on_at_start)201 void RegExpMacroAssemblerMIPS::CheckAtStart(Label* on_at_start) {
202   Label not_at_start;
203   // Did we start the match at the start of the string at all?
204   __ lw(a0, MemOperand(frame_pointer(), kAtStart));
205   BranchOrBacktrack(&not_at_start, eq, a0, Operand(zero_reg));
206 
207   // If we did, are we still at the start of the input?
208   __ lw(a1, MemOperand(frame_pointer(), kInputStart));
209   __ Addu(a0, end_of_input_address(), Operand(current_input_offset()));
210   BranchOrBacktrack(on_at_start, eq, a0, Operand(a1));
211   __ bind(&not_at_start);
212 }
213 
214 
CheckNotAtStart(Label * on_not_at_start)215 void RegExpMacroAssemblerMIPS::CheckNotAtStart(Label* on_not_at_start) {
216   // Did we start the match at the start of the string at all?
217   __ lw(a0, MemOperand(frame_pointer(), kAtStart));
218   BranchOrBacktrack(on_not_at_start, eq, a0, Operand(zero_reg));
219   // If we did, are we still at the start of the input?
220   __ lw(a1, MemOperand(frame_pointer(), kInputStart));
221   __ Addu(a0, end_of_input_address(), Operand(current_input_offset()));
222   BranchOrBacktrack(on_not_at_start, ne, a0, Operand(a1));
223 }
224 
225 
CheckCharacterLT(uc16 limit,Label * on_less)226 void RegExpMacroAssemblerMIPS::CheckCharacterLT(uc16 limit, Label* on_less) {
227   BranchOrBacktrack(on_less, lt, current_character(), Operand(limit));
228 }
229 
230 
CheckCharacters(Vector<const uc16> str,int cp_offset,Label * on_failure,bool check_end_of_string)231 void RegExpMacroAssemblerMIPS::CheckCharacters(Vector<const uc16> str,
232                                               int cp_offset,
233                                               Label* on_failure,
234                                               bool check_end_of_string) {
235   if (on_failure == NULL) {
236     // Instead of inlining a backtrack for each test, (re)use the global
237     // backtrack target.
238     on_failure = &backtrack_label_;
239   }
240 
241   if (check_end_of_string) {
242     // Is last character of required match inside string.
243     CheckPosition(cp_offset + str.length() - 1, on_failure);
244   }
245 
246   __ Addu(a0, end_of_input_address(), Operand(current_input_offset()));
247   if (cp_offset != 0) {
248     int byte_offset = cp_offset * char_size();
249     __ Addu(a0, a0, Operand(byte_offset));
250   }
251 
252   // a0 : Address of characters to match against str.
253   int stored_high_byte = 0;
254   for (int i = 0; i < str.length(); i++) {
255     if (mode_ == ASCII) {
256       __ lbu(a1, MemOperand(a0, 0));
257       __ addiu(a0, a0, char_size());
258       ASSERT(str[i] <= String::kMaxAsciiCharCode);
259       BranchOrBacktrack(on_failure, ne, a1, Operand(str[i]));
260     } else {
261       __ lhu(a1, MemOperand(a0, 0));
262       __ addiu(a0, a0, char_size());
263       uc16 match_char = str[i];
264       int match_high_byte = (match_char >> 8);
265       if (match_high_byte == 0) {
266         BranchOrBacktrack(on_failure, ne, a1, Operand(str[i]));
267       } else {
268         if (match_high_byte != stored_high_byte) {
269           __ li(a2, Operand(match_high_byte));
270           stored_high_byte = match_high_byte;
271         }
272         __ Addu(a3, a2, Operand(match_char & 0xff));
273         BranchOrBacktrack(on_failure, ne, a1, Operand(a3));
274       }
275     }
276   }
277 }
278 
279 
CheckGreedyLoop(Label * on_equal)280 void RegExpMacroAssemblerMIPS::CheckGreedyLoop(Label* on_equal) {
281   Label backtrack_non_equal;
282   __ lw(a0, MemOperand(backtrack_stackpointer(), 0));
283   __ Branch(&backtrack_non_equal, ne, current_input_offset(), Operand(a0));
284   __ Addu(backtrack_stackpointer(),
285           backtrack_stackpointer(),
286           Operand(kPointerSize));
287   __ bind(&backtrack_non_equal);
288   BranchOrBacktrack(on_equal, eq, current_input_offset(), Operand(a0));
289 }
290 
291 
CheckNotBackReferenceIgnoreCase(int start_reg,Label * on_no_match)292 void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
293     int start_reg,
294     Label* on_no_match) {
295   Label fallthrough;
296   __ lw(a0, register_location(start_reg));  // Index of start of capture.
297   __ lw(a1, register_location(start_reg + 1));  // Index of end of capture.
298   __ Subu(a1, a1, a0);  // Length of capture.
299 
300   // If length is zero, either the capture is empty or it is not participating.
301   // In either case succeed immediately.
302   __ Branch(&fallthrough, eq, a1, Operand(zero_reg));
303 
304   __ Addu(t5, a1, current_input_offset());
305   // Check that there are enough characters left in the input.
306   BranchOrBacktrack(on_no_match, gt, t5, Operand(zero_reg));
307 
308   if (mode_ == ASCII) {
309     Label success;
310     Label fail;
311     Label loop_check;
312 
313     // a0 - offset of start of capture.
314     // a1 - length of capture.
315     __ Addu(a0, a0, Operand(end_of_input_address()));
316     __ Addu(a2, end_of_input_address(), Operand(current_input_offset()));
317     __ Addu(a1, a0, Operand(a1));
318 
319     // a0 - Address of start of capture.
320     // a1 - Address of end of capture.
321     // a2 - Address of current input position.
322 
323     Label loop;
324     __ bind(&loop);
325     __ lbu(a3, MemOperand(a0, 0));
326     __ addiu(a0, a0, char_size());
327     __ lbu(t0, MemOperand(a2, 0));
328     __ addiu(a2, a2, char_size());
329 
330     __ Branch(&loop_check, eq, t0, Operand(a3));
331 
332     // Mismatch, try case-insensitive match (converting letters to lower-case).
333     __ Or(a3, a3, Operand(0x20));  // Convert capture character to lower-case.
334     __ Or(t0, t0, Operand(0x20));  // Also convert input character.
335     __ Branch(&fail, ne, t0, Operand(a3));
336     __ Subu(a3, a3, Operand('a'));
337     __ Branch(&fail, hi, a3, Operand('z' - 'a'));  // Is a3 a lowercase letter?
338 
339     __ bind(&loop_check);
340     __ Branch(&loop, lt, a0, Operand(a1));
341     __ jmp(&success);
342 
343     __ bind(&fail);
344     GoTo(on_no_match);
345 
346     __ bind(&success);
347     // Compute new value of character position after the matched part.
348     __ Subu(current_input_offset(), a2, end_of_input_address());
349   } else {
350     ASSERT(mode_ == UC16);
351     // Put regexp engine registers on stack.
352     RegList regexp_registers_to_retain = current_input_offset().bit() |
353         current_character().bit() | backtrack_stackpointer().bit();
354     __ MultiPush(regexp_registers_to_retain);
355 
356     int argument_count = 4;
357     __ PrepareCallCFunction(argument_count, a2);
358 
359     // a0 - offset of start of capture.
360     // a1 - length of capture.
361 
362     // Put arguments into arguments registers.
363     // Parameters are
364     //   a0: Address byte_offset1 - Address captured substring's start.
365     //   a1: Address byte_offset2 - Address of current character position.
366     //   a2: size_t byte_length - length of capture in bytes(!).
367     //   a3: Isolate* isolate.
368 
369     // Address of start of capture.
370     __ Addu(a0, a0, Operand(end_of_input_address()));
371     // Length of capture.
372     __ mov(a2, a1);
373     // Save length in callee-save register for use on return.
374     __ mov(s3, a1);
375     // Address of current input position.
376     __ Addu(a1, current_input_offset(), Operand(end_of_input_address()));
377     // Isolate.
378     __ li(a3, Operand(ExternalReference::isolate_address()));
379 
380     {
381       AllowExternalCallThatCantCauseGC scope(masm_);
382       ExternalReference function =
383           ExternalReference::re_case_insensitive_compare_uc16(masm_->isolate());
384       __ CallCFunction(function, argument_count);
385     }
386 
387     // Restore regexp engine registers.
388     __ MultiPop(regexp_registers_to_retain);
389     __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
390     __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
391 
392     // Check if function returned non-zero for success or zero for failure.
393     BranchOrBacktrack(on_no_match, eq, v0, Operand(zero_reg));
394     // On success, increment position by length of capture.
395     __ Addu(current_input_offset(), current_input_offset(), Operand(s3));
396   }
397 
398   __ bind(&fallthrough);
399 }
400 
401 
CheckNotBackReference(int start_reg,Label * on_no_match)402 void RegExpMacroAssemblerMIPS::CheckNotBackReference(
403     int start_reg,
404     Label* on_no_match) {
405   Label fallthrough;
406   Label success;
407 
408   // Find length of back-referenced capture.
409   __ lw(a0, register_location(start_reg));
410   __ lw(a1, register_location(start_reg + 1));
411   __ Subu(a1, a1, a0);  // Length to check.
412   // Succeed on empty capture (including no capture).
413   __ Branch(&fallthrough, eq, a1, Operand(zero_reg));
414 
415   __ Addu(t5, a1, current_input_offset());
416   // Check that there are enough characters left in the input.
417   BranchOrBacktrack(on_no_match, gt, t5, Operand(zero_reg));
418 
419   // Compute pointers to match string and capture string.
420   __ Addu(a0, a0, Operand(end_of_input_address()));
421   __ Addu(a2, end_of_input_address(), Operand(current_input_offset()));
422   __ Addu(a1, a1, Operand(a0));
423 
424   Label loop;
425   __ bind(&loop);
426   if (mode_ == ASCII) {
427     __ lbu(a3, MemOperand(a0, 0));
428     __ addiu(a0, a0, char_size());
429     __ lbu(t0, MemOperand(a2, 0));
430     __ addiu(a2, a2, char_size());
431   } else {
432     ASSERT(mode_ == UC16);
433     __ lhu(a3, MemOperand(a0, 0));
434     __ addiu(a0, a0, char_size());
435     __ lhu(t0, MemOperand(a2, 0));
436     __ addiu(a2, a2, char_size());
437   }
438   BranchOrBacktrack(on_no_match, ne, a3, Operand(t0));
439   __ Branch(&loop, lt, a0, Operand(a1));
440 
441   // Move current character position to position after match.
442   __ Subu(current_input_offset(), a2, end_of_input_address());
443   __ bind(&fallthrough);
444 }
445 
446 
CheckNotRegistersEqual(int reg1,int reg2,Label * on_not_equal)447 void RegExpMacroAssemblerMIPS::CheckNotRegistersEqual(int reg1,
448                                                       int reg2,
449                                                       Label* on_not_equal) {
450   UNIMPLEMENTED_MIPS();
451 }
452 
453 
CheckNotCharacter(uint32_t c,Label * on_not_equal)454 void RegExpMacroAssemblerMIPS::CheckNotCharacter(uint32_t c,
455                                                 Label* on_not_equal) {
456   BranchOrBacktrack(on_not_equal, ne, current_character(), Operand(c));
457 }
458 
459 
CheckCharacterAfterAnd(uint32_t c,uint32_t mask,Label * on_equal)460 void RegExpMacroAssemblerMIPS::CheckCharacterAfterAnd(uint32_t c,
461                                                      uint32_t mask,
462                                                      Label* on_equal) {
463   __ And(a0, current_character(), Operand(mask));
464   BranchOrBacktrack(on_equal, eq, a0, Operand(c));
465 }
466 
467 
CheckNotCharacterAfterAnd(uint32_t c,uint32_t mask,Label * on_not_equal)468 void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterAnd(uint32_t c,
469                                                         uint32_t mask,
470                                                         Label* on_not_equal) {
471   __ And(a0, current_character(), Operand(mask));
472   BranchOrBacktrack(on_not_equal, ne, a0, Operand(c));
473 }
474 
475 
CheckNotCharacterAfterMinusAnd(uc16 c,uc16 minus,uc16 mask,Label * on_not_equal)476 void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterMinusAnd(
477     uc16 c,
478     uc16 minus,
479     uc16 mask,
480     Label* on_not_equal) {
481   UNIMPLEMENTED_MIPS();
482 }
483 
484 
CheckSpecialCharacterClass(uc16 type,Label * on_no_match)485 bool RegExpMacroAssemblerMIPS::CheckSpecialCharacterClass(uc16 type,
486                                                          Label* on_no_match) {
487   // Range checks (c in min..max) are generally implemented by an unsigned
488   // (c - min) <= (max - min) check.
489   switch (type) {
490   case 's':
491     // Match space-characters.
492     if (mode_ == ASCII) {
493       // ASCII space characters are '\t'..'\r' and ' '.
494       Label success;
495       __ Branch(&success, eq, current_character(), Operand(' '));
496       // Check range 0x09..0x0d.
497       __ Subu(a0, current_character(), Operand('\t'));
498       BranchOrBacktrack(on_no_match, hi, a0, Operand('\r' - '\t'));
499       __ bind(&success);
500       return true;
501     }
502     return false;
503   case 'S':
504     // Match non-space characters.
505     if (mode_ == ASCII) {
506       // ASCII space characters are '\t'..'\r' and ' '.
507       BranchOrBacktrack(on_no_match, eq, current_character(), Operand(' '));
508       __ Subu(a0, current_character(), Operand('\t'));
509       BranchOrBacktrack(on_no_match, ls, a0, Operand('\r' - '\t'));
510       return true;
511     }
512     return false;
513   case 'd':
514     // Match ASCII digits ('0'..'9').
515     __ Subu(a0, current_character(), Operand('0'));
516     BranchOrBacktrack(on_no_match, hi, a0, Operand('9' - '0'));
517     return true;
518   case 'D':
519     // Match non ASCII-digits.
520     __ Subu(a0, current_character(), Operand('0'));
521     BranchOrBacktrack(on_no_match, ls, a0, Operand('9' - '0'));
522     return true;
523   case '.': {
524     // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029).
525     __ Xor(a0, current_character(), Operand(0x01));
526     // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c.
527     __ Subu(a0, a0, Operand(0x0b));
528     BranchOrBacktrack(on_no_match, ls, a0, Operand(0x0c - 0x0b));
529     if (mode_ == UC16) {
530       // Compare original value to 0x2028 and 0x2029, using the already
531       // computed (current_char ^ 0x01 - 0x0b). I.e., check for
532       // 0x201d (0x2028 - 0x0b) or 0x201e.
533       __ Subu(a0, a0, Operand(0x2028 - 0x0b));
534       BranchOrBacktrack(on_no_match, ls, a0, Operand(1));
535     }
536     return true;
537   }
538   case 'n': {
539     // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029).
540     __ Xor(a0, current_character(), Operand(0x01));
541     // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c.
542     __ Subu(a0, a0, Operand(0x0b));
543     if (mode_ == ASCII) {
544       BranchOrBacktrack(on_no_match, hi, a0, Operand(0x0c - 0x0b));
545     } else {
546       Label done;
547       BranchOrBacktrack(&done, ls, a0, Operand(0x0c - 0x0b));
548       // Compare original value to 0x2028 and 0x2029, using the already
549       // computed (current_char ^ 0x01 - 0x0b). I.e., check for
550       // 0x201d (0x2028 - 0x0b) or 0x201e.
551       __ Subu(a0, a0, Operand(0x2028 - 0x0b));
552       BranchOrBacktrack(on_no_match, hi, a0, Operand(1));
553       __ bind(&done);
554     }
555     return true;
556   }
557   case 'w': {
558     if (mode_ != ASCII) {
559       // Table is 128 entries, so all ASCII characters can be tested.
560       BranchOrBacktrack(on_no_match, hi, current_character(), Operand('z'));
561     }
562     ExternalReference map = ExternalReference::re_word_character_map();
563     __ li(a0, Operand(map));
564     __ Addu(a0, a0, current_character());
565     __ lbu(a0, MemOperand(a0, 0));
566     BranchOrBacktrack(on_no_match, eq, a0, Operand(zero_reg));
567     return true;
568   }
569   case 'W': {
570     Label done;
571     if (mode_ != ASCII) {
572       // Table is 128 entries, so all ASCII characters can be tested.
573       __ Branch(&done, hi, current_character(), Operand('z'));
574     }
575     ExternalReference map = ExternalReference::re_word_character_map();
576     __ li(a0, Operand(map));
577     __ Addu(a0, a0, current_character());
578     __ lbu(a0, MemOperand(a0, 0));
579     BranchOrBacktrack(on_no_match, ne, a0, Operand(zero_reg));
580     if (mode_ != ASCII) {
581       __ bind(&done);
582     }
583     return true;
584   }
585   case '*':
586     // Match any character.
587     return true;
588   // No custom implementation (yet): s(UC16), S(UC16).
589   default:
590     return false;
591   }
592 }
593 
594 
Fail()595 void RegExpMacroAssemblerMIPS::Fail() {
596   __ li(v0, Operand(FAILURE));
597   __ jmp(&exit_label_);
598 }
599 
600 
GetCode(Handle<String> source)601 Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
602   if (masm_->has_exception()) {
603     // If the code gets corrupted due to long regular expressions and lack of
604     // space on trampolines, an internal exception flag is set. If this case
605     // is detected, we will jump into exit sequence right away.
606     __ bind_to(&entry_label_, internal_failure_label_.pos());
607   } else {
608     // Finalize code - write the entry point code now we know how many
609     // registers we need.
610 
611     // Entry code:
612     __ bind(&entry_label_);
613 
614     // Tell the system that we have a stack frame.  Because the type is MANUAL,
615     // no is generated.
616     FrameScope scope(masm_, StackFrame::MANUAL);
617 
618     // Actually emit code to start a new stack frame.
619     // Push arguments
620     // Save callee-save registers.
621     // Start new stack frame.
622     // Store link register in existing stack-cell.
623     // Order here should correspond to order of offset constants in header file.
624     RegList registers_to_retain = s0.bit() | s1.bit() | s2.bit() |
625         s3.bit() | s4.bit() | s5.bit() | s6.bit() | s7.bit() | fp.bit();
626     RegList argument_registers = a0.bit() | a1.bit() | a2.bit() | a3.bit();
627     __ MultiPush(argument_registers | registers_to_retain | ra.bit());
628     // Set frame pointer in space for it if this is not a direct call
629     // from generated code.
630     __ Addu(frame_pointer(), sp, Operand(4 * kPointerSize));
631     __ push(a0);  // Make room for "position - 1" constant (value irrelevant).
632     __ push(a0);  // Make room for "at start" constant (value irrelevant).
633 
634     // Check if we have space on the stack for registers.
635     Label stack_limit_hit;
636     Label stack_ok;
637 
638     ExternalReference stack_limit =
639         ExternalReference::address_of_stack_limit(masm_->isolate());
640     __ li(a0, Operand(stack_limit));
641     __ lw(a0, MemOperand(a0));
642     __ Subu(a0, sp, a0);
643     // Handle it if the stack pointer is already below the stack limit.
644     __ Branch(&stack_limit_hit, le, a0, Operand(zero_reg));
645     // Check if there is room for the variable number of registers above
646     // the stack limit.
647     __ Branch(&stack_ok, hs, a0, Operand(num_registers_ * kPointerSize));
648     // Exit with OutOfMemory exception. There is not enough space on the stack
649     // for our working registers.
650     __ li(v0, Operand(EXCEPTION));
651     __ jmp(&exit_label_);
652 
653     __ bind(&stack_limit_hit);
654     CallCheckStackGuardState(a0);
655     // If returned value is non-zero, we exit with the returned value as result.
656     __ Branch(&exit_label_, ne, v0, Operand(zero_reg));
657 
658     __ bind(&stack_ok);
659     // Allocate space on stack for registers.
660     __ Subu(sp, sp, Operand(num_registers_ * kPointerSize));
661     // Load string end.
662     __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
663     // Load input start.
664     __ lw(a0, MemOperand(frame_pointer(), kInputStart));
665     // Find negative length (offset of start relative to end).
666     __ Subu(current_input_offset(), a0, end_of_input_address());
667     // Set a0 to address of char before start of the input string
668     // (effectively string position -1).
669     __ lw(a1, MemOperand(frame_pointer(), kStartIndex));
670     __ Subu(a0, current_input_offset(), Operand(char_size()));
671     __ sll(t5, a1, (mode_ == UC16) ? 1 : 0);
672     __ Subu(a0, a0, t5);
673     // Store this value in a local variable, for use when clearing
674     // position registers.
675     __ sw(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
676 
677     // Determine whether the start index is zero, that is at the start of the
678     // string, and store that value in a local variable.
679     __ mov(t5, a1);
680     __ li(a1, Operand(1));
681     __ Movn(a1, zero_reg, t5);
682     __ sw(a1, MemOperand(frame_pointer(), kAtStart));
683 
684     if (num_saved_registers_ > 0) {  // Always is, if generated from a regexp.
685       // Fill saved registers with initial value = start offset - 1.
686 
687       // Address of register 0.
688       __ Addu(a1, frame_pointer(), Operand(kRegisterZero));
689       __ li(a2, Operand(num_saved_registers_));
690       Label init_loop;
691       __ bind(&init_loop);
692       __ sw(a0, MemOperand(a1));
693       __ Addu(a1, a1, Operand(-kPointerSize));
694       __ Subu(a2, a2, Operand(1));
695       __ Branch(&init_loop, ne, a2, Operand(zero_reg));
696     }
697 
698     // Initialize backtrack stack pointer.
699     __ lw(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd));
700     // Initialize code pointer register
701     __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
702     // Load previous char as initial value of current character register.
703     Label at_start;
704     __ lw(a0, MemOperand(frame_pointer(), kAtStart));
705     __ Branch(&at_start, ne, a0, Operand(zero_reg));
706     LoadCurrentCharacterUnchecked(-1, 1);  // Load previous char.
707     __ jmp(&start_label_);
708     __ bind(&at_start);
709     __ li(current_character(), Operand('\n'));
710     __ jmp(&start_label_);
711 
712 
713     // Exit code:
714     if (success_label_.is_linked()) {
715       // Save captures when successful.
716       __ bind(&success_label_);
717       if (num_saved_registers_ > 0) {
718         // Copy captures to output.
719         __ lw(a1, MemOperand(frame_pointer(), kInputStart));
720         __ lw(a0, MemOperand(frame_pointer(), kRegisterOutput));
721         __ lw(a2, MemOperand(frame_pointer(), kStartIndex));
722         __ Subu(a1, end_of_input_address(), a1);
723         // a1 is length of input in bytes.
724         if (mode_ == UC16) {
725           __ srl(a1, a1, 1);
726         }
727         // a1 is length of input in characters.
728         __ Addu(a1, a1, Operand(a2));
729         // a1 is length of string in characters.
730 
731         ASSERT_EQ(0, num_saved_registers_ % 2);
732         // Always an even number of capture registers. This allows us to
733         // unroll the loop once to add an operation between a load of a register
734         // and the following use of that register.
735         for (int i = 0; i < num_saved_registers_; i += 2) {
736           __ lw(a2, register_location(i));
737           __ lw(a3, register_location(i + 1));
738           if (mode_ == UC16) {
739             __ sra(a2, a2, 1);
740             __ Addu(a2, a2, a1);
741             __ sra(a3, a3, 1);
742             __ Addu(a3, a3, a1);
743           } else {
744             __ Addu(a2, a1, Operand(a2));
745             __ Addu(a3, a1, Operand(a3));
746           }
747           __ sw(a2, MemOperand(a0));
748           __ Addu(a0, a0, kPointerSize);
749           __ sw(a3, MemOperand(a0));
750           __ Addu(a0, a0, kPointerSize);
751         }
752       }
753       __ li(v0, Operand(SUCCESS));
754     }
755     // Exit and return v0.
756     __ bind(&exit_label_);
757     // Skip sp past regexp registers and local variables..
758     __ mov(sp, frame_pointer());
759     // Restore registers s0..s7 and return (restoring ra to pc).
760     __ MultiPop(registers_to_retain | ra.bit());
761     __ Ret();
762 
763     // Backtrack code (branch target for conditional backtracks).
764     if (backtrack_label_.is_linked()) {
765       __ bind(&backtrack_label_);
766       Backtrack();
767     }
768 
769     Label exit_with_exception;
770 
771     // Preempt-code.
772     if (check_preempt_label_.is_linked()) {
773       SafeCallTarget(&check_preempt_label_);
774       // Put regexp engine registers on stack.
775       RegList regexp_registers_to_retain = current_input_offset().bit() |
776           current_character().bit() | backtrack_stackpointer().bit();
777       __ MultiPush(regexp_registers_to_retain);
778       CallCheckStackGuardState(a0);
779       __ MultiPop(regexp_registers_to_retain);
780       // If returning non-zero, we should end execution with the given
781       // result as return value.
782       __ Branch(&exit_label_, ne, v0, Operand(zero_reg));
783 
784       // String might have moved: Reload end of string from frame.
785       __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
786       __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
787       SafeReturn();
788     }
789 
790     // Backtrack stack overflow code.
791     if (stack_overflow_label_.is_linked()) {
792       SafeCallTarget(&stack_overflow_label_);
793       // Reached if the backtrack-stack limit has been hit.
794       // Put regexp engine registers on stack first.
795       RegList regexp_registers = current_input_offset().bit() |
796           current_character().bit();
797       __ MultiPush(regexp_registers);
798       Label grow_failed;
799       // Call GrowStack(backtrack_stackpointer(), &stack_base)
800       static const int num_arguments = 3;
801       __ PrepareCallCFunction(num_arguments, a0);
802       __ mov(a0, backtrack_stackpointer());
803       __ Addu(a1, frame_pointer(), Operand(kStackHighEnd));
804       __ li(a2, Operand(ExternalReference::isolate_address()));
805       ExternalReference grow_stack =
806           ExternalReference::re_grow_stack(masm_->isolate());
807       __ CallCFunction(grow_stack, num_arguments);
808       // Restore regexp registers.
809       __ MultiPop(regexp_registers);
810       // If return NULL, we have failed to grow the stack, and
811       // must exit with a stack-overflow exception.
812       __ Branch(&exit_with_exception, eq, v0, Operand(zero_reg));
813       // Otherwise use return value as new stack pointer.
814       __ mov(backtrack_stackpointer(), v0);
815       // Restore saved registers and continue.
816       __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
817       __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
818       SafeReturn();
819     }
820 
821     if (exit_with_exception.is_linked()) {
822       // If any of the code above needed to exit with an exception.
823       __ bind(&exit_with_exception);
824       // Exit with Result EXCEPTION(-1) to signal thrown exception.
825       __ li(v0, Operand(EXCEPTION));
826       __ jmp(&exit_label_);
827     }
828   }
829 
830   CodeDesc code_desc;
831   masm_->GetCode(&code_desc);
832   Handle<Code> code = FACTORY->NewCode(code_desc,
833                                        Code::ComputeFlags(Code::REGEXP),
834                                        masm_->CodeObject());
835   LOG(Isolate::Current(), RegExpCodeCreateEvent(*code, *source));
836   return Handle<HeapObject>::cast(code);
837 }
838 
839 
GoTo(Label * to)840 void RegExpMacroAssemblerMIPS::GoTo(Label* to) {
841   if (to == NULL) {
842     Backtrack();
843     return;
844   }
845   __ jmp(to);
846   return;
847 }
848 
849 
IfRegisterGE(int reg,int comparand,Label * if_ge)850 void RegExpMacroAssemblerMIPS::IfRegisterGE(int reg,
851                                            int comparand,
852                                            Label* if_ge) {
853   __ lw(a0, register_location(reg));
854     BranchOrBacktrack(if_ge, ge, a0, Operand(comparand));
855 }
856 
857 
IfRegisterLT(int reg,int comparand,Label * if_lt)858 void RegExpMacroAssemblerMIPS::IfRegisterLT(int reg,
859                                            int comparand,
860                                            Label* if_lt) {
861   __ lw(a0, register_location(reg));
862   BranchOrBacktrack(if_lt, lt, a0, Operand(comparand));
863 }
864 
865 
IfRegisterEqPos(int reg,Label * if_eq)866 void RegExpMacroAssemblerMIPS::IfRegisterEqPos(int reg,
867                                               Label* if_eq) {
868   __ lw(a0, register_location(reg));
869   BranchOrBacktrack(if_eq, eq, a0, Operand(current_input_offset()));
870 }
871 
872 
873 RegExpMacroAssembler::IrregexpImplementation
Implementation()874     RegExpMacroAssemblerMIPS::Implementation() {
875   return kMIPSImplementation;
876 }
877 
878 
LoadCurrentCharacter(int cp_offset,Label * on_end_of_input,bool check_bounds,int characters)879 void RegExpMacroAssemblerMIPS::LoadCurrentCharacter(int cp_offset,
880                                                    Label* on_end_of_input,
881                                                    bool check_bounds,
882                                                    int characters) {
883   ASSERT(cp_offset >= -1);      // ^ and \b can look behind one character.
884   ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works).
885   if (check_bounds) {
886     CheckPosition(cp_offset + characters - 1, on_end_of_input);
887   }
888   LoadCurrentCharacterUnchecked(cp_offset, characters);
889 }
890 
891 
PopCurrentPosition()892 void RegExpMacroAssemblerMIPS::PopCurrentPosition() {
893   Pop(current_input_offset());
894 }
895 
896 
PopRegister(int register_index)897 void RegExpMacroAssemblerMIPS::PopRegister(int register_index) {
898   Pop(a0);
899   __ sw(a0, register_location(register_index));
900 }
901 
902 
PushBacktrack(Label * label)903 void RegExpMacroAssemblerMIPS::PushBacktrack(Label* label) {
904   if (label->is_bound()) {
905     int target = label->pos();
906     __ li(a0, Operand(target + Code::kHeaderSize - kHeapObjectTag));
907   } else {
908     Label after_constant;
909     __ Branch(&after_constant);
910     int offset = masm_->pc_offset();
911     int cp_offset = offset + Code::kHeaderSize - kHeapObjectTag;
912     __ emit(0);
913     masm_->label_at_put(label, offset);
914     __ bind(&after_constant);
915     if (is_int16(cp_offset)) {
916       __ lw(a0, MemOperand(code_pointer(), cp_offset));
917     } else {
918       __ Addu(a0, code_pointer(), cp_offset);
919       __ lw(a0, MemOperand(a0, 0));
920     }
921   }
922   Push(a0);
923   CheckStackLimit();
924 }
925 
926 
PushCurrentPosition()927 void RegExpMacroAssemblerMIPS::PushCurrentPosition() {
928   Push(current_input_offset());
929 }
930 
931 
PushRegister(int register_index,StackCheckFlag check_stack_limit)932 void RegExpMacroAssemblerMIPS::PushRegister(int register_index,
933                                            StackCheckFlag check_stack_limit) {
934   __ lw(a0, register_location(register_index));
935   Push(a0);
936   if (check_stack_limit) CheckStackLimit();
937 }
938 
939 
ReadCurrentPositionFromRegister(int reg)940 void RegExpMacroAssemblerMIPS::ReadCurrentPositionFromRegister(int reg) {
941   __ lw(current_input_offset(), register_location(reg));
942 }
943 
944 
ReadStackPointerFromRegister(int reg)945 void RegExpMacroAssemblerMIPS::ReadStackPointerFromRegister(int reg) {
946   __ lw(backtrack_stackpointer(), register_location(reg));
947   __ lw(a0, MemOperand(frame_pointer(), kStackHighEnd));
948   __ Addu(backtrack_stackpointer(), backtrack_stackpointer(), Operand(a0));
949 }
950 
951 
SetCurrentPositionFromEnd(int by)952 void RegExpMacroAssemblerMIPS::SetCurrentPositionFromEnd(int by) {
953   Label after_position;
954   __ Branch(&after_position,
955             ge,
956             current_input_offset(),
957             Operand(-by * char_size()));
958   __ li(current_input_offset(), -by * char_size());
959   // On RegExp code entry (where this operation is used), the character before
960   // the current position is expected to be already loaded.
961   // We have advanced the position, so it's safe to read backwards.
962   LoadCurrentCharacterUnchecked(-1, 1);
963   __ bind(&after_position);
964 }
965 
966 
SetRegister(int register_index,int to)967 void RegExpMacroAssemblerMIPS::SetRegister(int register_index, int to) {
968   ASSERT(register_index >= num_saved_registers_);  // Reserved for positions!
969   __ li(a0, Operand(to));
970   __ sw(a0, register_location(register_index));
971 }
972 
973 
Succeed()974 void RegExpMacroAssemblerMIPS::Succeed() {
975   __ jmp(&success_label_);
976 }
977 
978 
WriteCurrentPositionToRegister(int reg,int cp_offset)979 void RegExpMacroAssemblerMIPS::WriteCurrentPositionToRegister(int reg,
980                                                              int cp_offset) {
981   if (cp_offset == 0) {
982     __ sw(current_input_offset(), register_location(reg));
983   } else {
984     __ Addu(a0, current_input_offset(), Operand(cp_offset * char_size()));
985     __ sw(a0, register_location(reg));
986   }
987 }
988 
989 
ClearRegisters(int reg_from,int reg_to)990 void RegExpMacroAssemblerMIPS::ClearRegisters(int reg_from, int reg_to) {
991   ASSERT(reg_from <= reg_to);
992   __ lw(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
993   for (int reg = reg_from; reg <= reg_to; reg++) {
994     __ sw(a0, register_location(reg));
995   }
996 }
997 
998 
WriteStackPointerToRegister(int reg)999 void RegExpMacroAssemblerMIPS::WriteStackPointerToRegister(int reg) {
1000   __ lw(a1, MemOperand(frame_pointer(), kStackHighEnd));
1001   __ Subu(a0, backtrack_stackpointer(), a1);
1002   __ sw(a0, register_location(reg));
1003 }
1004 
1005 
1006 // Private methods:
1007 
CallCheckStackGuardState(Register scratch)1008 void RegExpMacroAssemblerMIPS::CallCheckStackGuardState(Register scratch) {
1009   static const int num_arguments = 3;
1010   __ PrepareCallCFunction(num_arguments, scratch);
1011   __ mov(a2, frame_pointer());
1012   // Code* of self.
1013   __ li(a1, Operand(masm_->CodeObject()), CONSTANT_SIZE);
1014   // a0 becomes return address pointer.
1015   ExternalReference stack_guard_check =
1016       ExternalReference::re_check_stack_guard_state(masm_->isolate());
1017   CallCFunctionUsingStub(stack_guard_check, num_arguments);
1018 }
1019 
1020 
1021 // Helper function for reading a value out of a stack frame.
1022 template <typename T>
frame_entry(Address re_frame,int frame_offset)1023 static T& frame_entry(Address re_frame, int frame_offset) {
1024   return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
1025 }
1026 
1027 
CheckStackGuardState(Address * return_address,Code * re_code,Address re_frame)1028 int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address,
1029                                                    Code* re_code,
1030                                                    Address re_frame) {
1031   Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
1032   ASSERT(isolate == Isolate::Current());
1033   if (isolate->stack_guard()->IsStackOverflow()) {
1034     isolate->StackOverflow();
1035     return EXCEPTION;
1036   }
1037 
1038   // If not real stack overflow the stack guard was used to interrupt
1039   // execution for another purpose.
1040 
1041   // If this is a direct call from JavaScript retry the RegExp forcing the call
1042   // through the runtime system. Currently the direct call cannot handle a GC.
1043   if (frame_entry<int>(re_frame, kDirectCall) == 1) {
1044     return RETRY;
1045   }
1046 
1047   // Prepare for possible GC.
1048   HandleScope handles(isolate);
1049   Handle<Code> code_handle(re_code);
1050 
1051   Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
1052   // Current string.
1053   bool is_ascii = subject->IsAsciiRepresentationUnderneath();
1054 
1055   ASSERT(re_code->instruction_start() <= *return_address);
1056   ASSERT(*return_address <=
1057       re_code->instruction_start() + re_code->instruction_size());
1058 
1059   MaybeObject* result = Execution::HandleStackGuardInterrupt(isolate);
1060 
1061   if (*code_handle != re_code) {  // Return address no longer valid.
1062     int delta = code_handle->address() - re_code->address();
1063     // Overwrite the return address on the stack.
1064     *return_address += delta;
1065   }
1066 
1067   if (result->IsException()) {
1068     return EXCEPTION;
1069   }
1070 
1071   Handle<String> subject_tmp = subject;
1072   int slice_offset = 0;
1073 
1074   // Extract the underlying string and the slice offset.
1075   if (StringShape(*subject_tmp).IsCons()) {
1076     subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
1077   } else if (StringShape(*subject_tmp).IsSliced()) {
1078     SlicedString* slice = SlicedString::cast(*subject_tmp);
1079     subject_tmp = Handle<String>(slice->parent());
1080     slice_offset = slice->offset();
1081   }
1082 
1083   // String might have changed.
1084   if (subject_tmp->IsAsciiRepresentation() != is_ascii) {
1085     // If we changed between an ASCII and an UC16 string, the specialized
1086     // code cannot be used, and we need to restart regexp matching from
1087     // scratch (including, potentially, compiling a new version of the code).
1088     return RETRY;
1089   }
1090 
1091   // Otherwise, the content of the string might have moved. It must still
1092   // be a sequential or external string with the same content.
1093   // Update the start and end pointers in the stack frame to the current
1094   // location (whether it has actually moved or not).
1095   ASSERT(StringShape(*subject_tmp).IsSequential() ||
1096       StringShape(*subject_tmp).IsExternal());
1097 
1098   // The original start address of the characters to match.
1099   const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
1100 
1101   // Find the current start address of the same character at the current string
1102   // position.
1103   int start_index = frame_entry<int>(re_frame, kStartIndex);
1104   const byte* new_address = StringCharacterPosition(*subject_tmp,
1105                                                     start_index + slice_offset);
1106 
1107   if (start_address != new_address) {
1108     // If there is a difference, update the object pointer and start and end
1109     // addresses in the RegExp stack frame to match the new value.
1110     const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
1111     int byte_length = static_cast<int>(end_address - start_address);
1112     frame_entry<const String*>(re_frame, kInputString) = *subject;
1113     frame_entry<const byte*>(re_frame, kInputStart) = new_address;
1114     frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
1115   } else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
1116     // Subject string might have been a ConsString that underwent
1117     // short-circuiting during GC. That will not change start_address but
1118     // will change pointer inside the subject handle.
1119     frame_entry<const String*>(re_frame, kInputString) = *subject;
1120   }
1121 
1122   return 0;
1123 }
1124 
1125 
register_location(int register_index)1126 MemOperand RegExpMacroAssemblerMIPS::register_location(int register_index) {
1127   ASSERT(register_index < (1<<30));
1128   if (num_registers_ <= register_index) {
1129     num_registers_ = register_index + 1;
1130   }
1131   return MemOperand(frame_pointer(),
1132                     kRegisterZero - register_index * kPointerSize);
1133 }
1134 
1135 
CheckPosition(int cp_offset,Label * on_outside_input)1136 void RegExpMacroAssemblerMIPS::CheckPosition(int cp_offset,
1137                                             Label* on_outside_input) {
1138   BranchOrBacktrack(on_outside_input,
1139                     ge,
1140                     current_input_offset(),
1141                     Operand(-cp_offset * char_size()));
1142 }
1143 
1144 
BranchOrBacktrack(Label * to,Condition condition,Register rs,const Operand & rt)1145 void RegExpMacroAssemblerMIPS::BranchOrBacktrack(Label* to,
1146                                                  Condition condition,
1147                                                  Register rs,
1148                                                  const Operand& rt) {
1149   if (condition == al) {  // Unconditional.
1150     if (to == NULL) {
1151       Backtrack();
1152       return;
1153     }
1154     __ jmp(to);
1155     return;
1156   }
1157   if (to == NULL) {
1158     __ Branch(&backtrack_label_, condition, rs, rt);
1159     return;
1160   }
1161   __ Branch(to, condition, rs, rt);
1162 }
1163 
1164 
SafeCall(Label * to,Condition cond,Register rs,const Operand & rt)1165 void RegExpMacroAssemblerMIPS::SafeCall(Label* to, Condition cond, Register rs,
1166                                            const Operand& rt) {
1167   __ BranchAndLink(to, cond, rs, rt);
1168 }
1169 
1170 
SafeReturn()1171 void RegExpMacroAssemblerMIPS::SafeReturn() {
1172   __ pop(ra);
1173   __ Addu(t5, ra, Operand(masm_->CodeObject()));
1174   __ Jump(t5);
1175 }
1176 
1177 
SafeCallTarget(Label * name)1178 void RegExpMacroAssemblerMIPS::SafeCallTarget(Label* name) {
1179   __ bind(name);
1180   __ Subu(ra, ra, Operand(masm_->CodeObject()));
1181   __ push(ra);
1182 }
1183 
1184 
Push(Register source)1185 void RegExpMacroAssemblerMIPS::Push(Register source) {
1186   ASSERT(!source.is(backtrack_stackpointer()));
1187   __ Addu(backtrack_stackpointer(),
1188           backtrack_stackpointer(),
1189           Operand(-kPointerSize));
1190   __ sw(source, MemOperand(backtrack_stackpointer()));
1191 }
1192 
1193 
Pop(Register target)1194 void RegExpMacroAssemblerMIPS::Pop(Register target) {
1195   ASSERT(!target.is(backtrack_stackpointer()));
1196   __ lw(target, MemOperand(backtrack_stackpointer()));
1197   __ Addu(backtrack_stackpointer(), backtrack_stackpointer(), kPointerSize);
1198 }
1199 
1200 
CheckPreemption()1201 void RegExpMacroAssemblerMIPS::CheckPreemption() {
1202   // Check for preemption.
1203   ExternalReference stack_limit =
1204       ExternalReference::address_of_stack_limit(masm_->isolate());
1205   __ li(a0, Operand(stack_limit));
1206   __ lw(a0, MemOperand(a0));
1207   SafeCall(&check_preempt_label_, ls, sp, Operand(a0));
1208 }
1209 
1210 
CheckStackLimit()1211 void RegExpMacroAssemblerMIPS::CheckStackLimit() {
1212   ExternalReference stack_limit =
1213       ExternalReference::address_of_regexp_stack_limit(masm_->isolate());
1214 
1215   __ li(a0, Operand(stack_limit));
1216   __ lw(a0, MemOperand(a0));
1217   SafeCall(&stack_overflow_label_, ls, backtrack_stackpointer(), Operand(a0));
1218 }
1219 
1220 
CallCFunctionUsingStub(ExternalReference function,int num_arguments)1221 void RegExpMacroAssemblerMIPS::CallCFunctionUsingStub(
1222     ExternalReference function,
1223     int num_arguments) {
1224   // Must pass all arguments in registers. The stub pushes on the stack.
1225   ASSERT(num_arguments <= 4);
1226   __ li(code_pointer(), Operand(function));
1227   RegExpCEntryStub stub;
1228   __ CallStub(&stub);
1229   if (OS::ActivationFrameAlignment() != 0) {
1230     __ lw(sp, MemOperand(sp, 16));
1231   }
1232   __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
1233 }
1234 
1235 
LoadCurrentCharacterUnchecked(int cp_offset,int characters)1236 void RegExpMacroAssemblerMIPS::LoadCurrentCharacterUnchecked(int cp_offset,
1237                                                             int characters) {
1238   Register offset = current_input_offset();
1239   if (cp_offset != 0) {
1240     __ Addu(a0, current_input_offset(), Operand(cp_offset * char_size()));
1241     offset = a0;
1242   }
1243   // We assume that we cannot do unaligned loads on MIPS, so this function
1244   // must only be used to load a single character at a time.
1245   ASSERT(characters == 1);
1246   __ Addu(t5, end_of_input_address(), Operand(offset));
1247   if (mode_ == ASCII) {
1248     __ lbu(current_character(), MemOperand(t5, 0));
1249   } else {
1250     ASSERT(mode_ == UC16);
1251     __ lhu(current_character(), MemOperand(t5, 0));
1252   }
1253 }
1254 
1255 
Generate(MacroAssembler * masm_)1256 void RegExpCEntryStub::Generate(MacroAssembler* masm_) {
1257   int stack_alignment = OS::ActivationFrameAlignment();
1258   if (stack_alignment < kPointerSize) stack_alignment = kPointerSize;
1259   // Stack is already aligned for call, so decrement by alignment
1260   // to make room for storing the return address.
1261   __ Subu(sp, sp, Operand(stack_alignment + kCArgsSlotsSize));
1262   const int return_address_offset = kCArgsSlotsSize;
1263   __ Addu(a0, sp, return_address_offset);
1264   __ sw(ra, MemOperand(a0, 0));
1265   __ mov(t9, t1);
1266   __ Call(t9);
1267   __ lw(ra, MemOperand(sp, return_address_offset));
1268   __ Addu(sp, sp, Operand(stack_alignment + kCArgsSlotsSize));
1269   __ Jump(ra);
1270 }
1271 
1272 
1273 #undef __
1274 
1275 #endif  // V8_INTERPRETED_REGEXP
1276 
1277 }}  // namespace v8::internal
1278 
1279 #endif  // V8_TARGET_ARCH_MIPS
1280