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